1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Config.cpp: Implements the egl::Config class, describing the format, type 16 // and size for an egl::Surface. Implements EGLConfig and related functionality. 17 // [EGL 1.4] section 3.4 page 15. 18 19 #include "Config.h" 20 21 #include "common/debug.h" 22 23 #include <EGL/eglext.h> 24 #ifdef __ANDROID__ 25 #include <system/graphics.h> 26 #endif 27 28 #include <string.h> 29 #include <algorithm> 30 #include <cstring> 31 #include <vector> 32 #include <map> 33 34 using namespace std; 35 36 namespace egl 37 { 38 39 Config::Config(sw::Format displayFormat, EGLint minInterval, EGLint maxInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample) 40 : mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample) 41 { 42 mBindToTextureRGB = EGL_FALSE; 43 mBindToTextureRGBA = EGL_FALSE; 44 45 // Initialize to a high value to lower the preference of formats for which there's no native support 46 mNativeVisualID = 0x7FFFFFFF; 47 48 switch(renderTargetFormat) 49 { 50 case sw::FORMAT_A1R5G5B5: 51 mRedSize = 5; 52 mGreenSize = 5; 53 mBlueSize = 5; 54 mAlphaSize = 1; 55 break; 56 case sw::FORMAT_A2R10G10B10: 57 mRedSize = 10; 58 mGreenSize = 10; 59 mBlueSize = 10; 60 mAlphaSize = 2; 61 break; 62 case sw::FORMAT_A8R8G8B8: 63 mRedSize = 8; 64 mGreenSize = 8; 65 mBlueSize = 8; 66 mAlphaSize = 8; 67 mBindToTextureRGBA = EGL_TRUE; 68 #ifdef __ANDROID__ 69 mNativeVisualID = HAL_PIXEL_FORMAT_BGRA_8888; 70 #else 71 mNativeVisualID = 2; // Arbitrary; prefer over ABGR 72 #endif 73 break; 74 case sw::FORMAT_A8B8G8R8: 75 mRedSize = 8; 76 mGreenSize = 8; 77 mBlueSize = 8; 78 mAlphaSize = 8; 79 mBindToTextureRGBA = EGL_TRUE; 80 #ifdef __ANDROID__ 81 mNativeVisualID = HAL_PIXEL_FORMAT_RGBA_8888; 82 #endif 83 break; 84 case sw::FORMAT_R5G6B5: 85 mRedSize = 5; 86 mGreenSize = 6; 87 mBlueSize = 5; 88 mAlphaSize = 0; 89 #ifdef __ANDROID__ 90 mNativeVisualID = HAL_PIXEL_FORMAT_RGB_565; 91 #endif 92 break; 93 case sw::FORMAT_X8R8G8B8: 94 mRedSize = 8; 95 mGreenSize = 8; 96 mBlueSize = 8; 97 mAlphaSize = 0; 98 mBindToTextureRGB = EGL_TRUE; 99 #ifdef __ANDROID__ 100 mNativeVisualID = 0x1FF; // HAL_PIXEL_FORMAT_BGRX_8888 101 #else 102 mNativeVisualID = 1; // Arbitrary; prefer over XBGR 103 #endif 104 break; 105 case sw::FORMAT_X8B8G8R8: 106 mRedSize = 8; 107 mGreenSize = 8; 108 mBlueSize = 8; 109 mAlphaSize = 0; 110 mBindToTextureRGB = EGL_TRUE; 111 #ifdef __ANDROID__ 112 mNativeVisualID = HAL_PIXEL_FORMAT_RGBX_8888; 113 #endif 114 break; 115 default: 116 UNREACHABLE(renderTargetFormat); 117 } 118 119 mLuminanceSize = 0; 120 mBufferSize = mRedSize + mGreenSize + mBlueSize + mLuminanceSize + mAlphaSize; 121 mAlphaMaskSize = 0; 122 mColorBufferType = EGL_RGB_BUFFER; 123 mConfigCaveat = EGL_NONE; 124 mConfigID = 0; 125 mConformant = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT; 126 127 switch(depthStencilFormat) 128 { 129 case sw::FORMAT_NULL: 130 mDepthSize = 0; 131 mStencilSize = 0; 132 break; 133 // case sw::FORMAT_D16_LOCKABLE: 134 // mDepthSize = 16; 135 // mStencilSize = 0; 136 // break; 137 case sw::FORMAT_D32: 138 mDepthSize = 32; 139 mStencilSize = 0; 140 break; 141 // case sw::FORMAT_D15S1: 142 // mDepthSize = 15; 143 // mStencilSize = 1; 144 // break; 145 case sw::FORMAT_D24S8: 146 mDepthSize = 24; 147 mStencilSize = 8; 148 break; 149 case sw::FORMAT_D24X8: 150 mDepthSize = 24; 151 mStencilSize = 0; 152 break; 153 // case sw::FORMAT_D24X4S4: 154 // mDepthSize = 24; 155 // mStencilSize = 4; 156 // break; 157 case sw::FORMAT_D16: 158 mDepthSize = 16; 159 mStencilSize = 0; 160 break; 161 // case sw::FORMAT_D32F_LOCKABLE: 162 // mDepthSize = 32; 163 // mStencilSize = 0; 164 // break; 165 // case sw::FORMAT_D24FS8: 166 // mDepthSize = 24; 167 // mStencilSize = 8; 168 // break; 169 default: 170 UNREACHABLE(depthStencilFormat); 171 } 172 173 mLevel = 0; 174 mMatchNativePixmap = EGL_NONE; 175 mMaxPBufferWidth = 4096; 176 mMaxPBufferHeight = 4096; 177 mMaxPBufferPixels = mMaxPBufferWidth * mMaxPBufferHeight; 178 mMaxSwapInterval = maxInterval; 179 mMinSwapInterval = minInterval; 180 mNativeRenderable = EGL_FALSE; 181 mNativeVisualType = 0; 182 mRenderableType = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT; 183 mSampleBuffers = (multiSample > 0) ? 1 : 0; 184 mSamples = multiSample; 185 mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT | EGL_MULTISAMPLE_RESOLVE_BOX_BIT; 186 mTransparentType = EGL_NONE; 187 mTransparentRedValue = 0; 188 mTransparentGreenValue = 0; 189 mTransparentBlueValue = 0; 190 191 // Although we could support any format as an Android HWComposer compatible config by converting when necessary, 192 // the intent of EGL_ANDROID_framebuffer_target is to prevent any copies or conversions. 193 mFramebufferTargetAndroid = (displayFormat == renderTargetFormat) ? EGL_TRUE : EGL_FALSE; 194 mRecordableAndroid = EGL_TRUE; 195 } 196 197 EGLConfig Config::getHandle() const 198 { 199 return (EGLConfig)(size_t)mConfigID; 200 } 201 202 // This ordering determines the config ID 203 bool CompareConfig::operator()(const Config &x, const Config &y) const 204 { 205 #define SORT_SMALLER(attribute) \ 206 if(x.attribute != y.attribute) \ 207 { \ 208 return x.attribute < y.attribute; \ 209 } 210 211 static_assert(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG, ""); 212 SORT_SMALLER(mConfigCaveat); 213 214 static_assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER, ""); 215 SORT_SMALLER(mColorBufferType); 216 217 SORT_SMALLER(mRedSize); 218 SORT_SMALLER(mGreenSize); 219 SORT_SMALLER(mBlueSize); 220 SORT_SMALLER(mAlphaSize); 221 222 SORT_SMALLER(mBufferSize); 223 SORT_SMALLER(mSampleBuffers); 224 SORT_SMALLER(mSamples); 225 SORT_SMALLER(mDepthSize); 226 SORT_SMALLER(mStencilSize); 227 SORT_SMALLER(mAlphaMaskSize); 228 SORT_SMALLER(mNativeVisualType); 229 SORT_SMALLER(mNativeVisualID); 230 231 #undef SORT_SMALLER 232 233 // Strict ordering requires sorting all non-equal fields above 234 assert(memcmp(&x, &y, sizeof(Config)) == 0); 235 236 return false; 237 } 238 239 // Function object used by STL sorting routines for ordering Configs according to [EGL] section 3.4.1 page 24. 240 class SortConfig 241 { 242 public: 243 explicit SortConfig(const EGLint *attribList); 244 245 bool operator()(const Config *x, const Config *y) const; 246 247 private: 248 EGLint wantedComponentsSize(const Config *config) const; 249 250 bool mWantRed; 251 bool mWantGreen; 252 bool mWantBlue; 253 bool mWantAlpha; 254 bool mWantLuminance; 255 }; 256 257 SortConfig::SortConfig(const EGLint *attribList) 258 : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false) 259 { 260 // [EGL] section 3.4.1 page 24 261 // Sorting rule #3: by larger total number of color bits, 262 // not considering components that are 0 or don't-care. 263 for(const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2) 264 { 265 // When multiple instances of the same attribute are present, last wins. 266 bool isSpecified = attr[1] && attr[1] != EGL_DONT_CARE; 267 switch(attr[0]) 268 { 269 case EGL_RED_SIZE: mWantRed = isSpecified; break; 270 case EGL_GREEN_SIZE: mWantGreen = isSpecified; break; 271 case EGL_BLUE_SIZE: mWantBlue = isSpecified; break; 272 case EGL_ALPHA_SIZE: mWantAlpha = isSpecified; break; 273 case EGL_LUMINANCE_SIZE: mWantLuminance = isSpecified; break; 274 } 275 } 276 } 277 278 EGLint SortConfig::wantedComponentsSize(const Config *config) const 279 { 280 EGLint total = 0; 281 282 if(mWantRed) total += config->mRedSize; 283 if(mWantGreen) total += config->mGreenSize; 284 if(mWantBlue) total += config->mBlueSize; 285 if(mWantAlpha) total += config->mAlphaSize; 286 if(mWantLuminance) total += config->mLuminanceSize; 287 288 return total; 289 } 290 291 bool SortConfig::operator()(const Config *x, const Config *y) const 292 { 293 #define SORT_SMALLER(attribute) \ 294 if(x->attribute != y->attribute) \ 295 { \ 296 return x->attribute < y->attribute; \ 297 } 298 299 static_assert(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG, ""); 300 SORT_SMALLER(mConfigCaveat); 301 302 static_assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER, ""); 303 SORT_SMALLER(mColorBufferType); 304 305 // By larger total number of color bits, only considering those that are requested to be > 0. 306 EGLint xComponentsSize = wantedComponentsSize(x); 307 EGLint yComponentsSize = wantedComponentsSize(y); 308 if(xComponentsSize != yComponentsSize) 309 { 310 return xComponentsSize > yComponentsSize; 311 } 312 313 SORT_SMALLER(mBufferSize); 314 SORT_SMALLER(mSampleBuffers); 315 SORT_SMALLER(mSamples); 316 SORT_SMALLER(mDepthSize); 317 SORT_SMALLER(mStencilSize); 318 SORT_SMALLER(mAlphaMaskSize); 319 SORT_SMALLER(mNativeVisualType); 320 SORT_SMALLER(mConfigID); 321 322 #undef SORT_SMALLER 323 324 return false; 325 } 326 327 ConfigSet::ConfigSet() 328 { 329 } 330 331 void ConfigSet::add(sw::Format displayFormat, EGLint minSwapInterval, EGLint maxSwapInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample) 332 { 333 Config conformantConfig(displayFormat, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample); 334 mSet.insert(conformantConfig); 335 } 336 337 size_t ConfigSet::size() const 338 { 339 return mSet.size(); 340 } 341 342 bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) 343 { 344 vector<const Config*> passed; 345 passed.reserve(mSet.size()); 346 347 /* Conformance expects for multiple instances of the same attribute that the 348 * last instance `wins`. Reduce the attribute list first to comply with 349 * this. 350 */ 351 /* TODO: C++11: unordered_map would be fine here */ 352 map<EGLint, EGLint> attribs; 353 const EGLint *attribute = attribList; 354 while (attribute[0] != EGL_NONE) 355 { 356 attribs[attribute[0]] = attribute[1]; 357 attribute += 2; 358 } 359 360 for(Iterator config = mSet.begin(); config != mSet.end(); config++) 361 { 362 bool match = true; 363 bool caveatMatch = (config->mConfigCaveat == EGL_NONE); 364 for (map<EGLint, EGLint>::iterator attribIt = attribs.begin(); attribIt != attribs.end(); attribIt++) 365 { 366 if(attribIt->second != EGL_DONT_CARE) 367 { 368 switch(attribIt->first) 369 { 370 case EGL_BUFFER_SIZE: match = config->mBufferSize >= attribIt->second; break; 371 case EGL_ALPHA_SIZE: match = config->mAlphaSize >= attribIt->second; break; 372 case EGL_BLUE_SIZE: match = config->mBlueSize >= attribIt->second; break; 373 case EGL_GREEN_SIZE: match = config->mGreenSize >= attribIt->second; break; 374 case EGL_RED_SIZE: match = config->mRedSize >= attribIt->second; break; 375 case EGL_DEPTH_SIZE: match = config->mDepthSize >= attribIt->second; break; 376 case EGL_STENCIL_SIZE: match = config->mStencilSize >= attribIt->second; break; 377 case EGL_CONFIG_CAVEAT: match = config->mConfigCaveat == (EGLenum)attribIt->second; break; 378 case EGL_CONFIG_ID: match = config->mConfigID == attribIt->second; break; 379 case EGL_LEVEL: match = config->mLevel >= attribIt->second; break; 380 case EGL_NATIVE_RENDERABLE: match = config->mNativeRenderable == (EGLBoolean)attribIt->second; break; 381 case EGL_NATIVE_VISUAL_TYPE: match = config->mNativeVisualType == attribIt->second; break; 382 case EGL_SAMPLES: match = config->mSamples >= attribIt->second; break; 383 case EGL_SAMPLE_BUFFERS: match = config->mSampleBuffers >= attribIt->second; break; 384 case EGL_SURFACE_TYPE: match = (config->mSurfaceType & attribIt->second) == attribIt->second; break; 385 case EGL_TRANSPARENT_TYPE: match = config->mTransparentType == (EGLenum)attribIt->second; break; 386 case EGL_TRANSPARENT_BLUE_VALUE: match = config->mTransparentBlueValue == attribIt->second; break; 387 case EGL_TRANSPARENT_GREEN_VALUE: match = config->mTransparentGreenValue == attribIt->second; break; 388 case EGL_TRANSPARENT_RED_VALUE: match = config->mTransparentRedValue == attribIt->second; break; 389 case EGL_BIND_TO_TEXTURE_RGB: match = config->mBindToTextureRGB == (EGLBoolean)attribIt->second; break; 390 case EGL_BIND_TO_TEXTURE_RGBA: match = config->mBindToTextureRGBA == (EGLBoolean)attribIt->second; break; 391 case EGL_MIN_SWAP_INTERVAL: match = config->mMinSwapInterval == attribIt->second; break; 392 case EGL_MAX_SWAP_INTERVAL: match = config->mMaxSwapInterval == attribIt->second; break; 393 case EGL_LUMINANCE_SIZE: match = config->mLuminanceSize >= attribIt->second; break; 394 case EGL_ALPHA_MASK_SIZE: match = config->mAlphaMaskSize >= attribIt->second; break; 395 case EGL_COLOR_BUFFER_TYPE: match = config->mColorBufferType == (EGLenum)attribIt->second; break; 396 case EGL_RENDERABLE_TYPE: match = (config->mRenderableType & attribIt->second) == attribIt->second; break; 397 case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break; 398 case EGL_CONFORMANT: match = (config->mConformant & attribIt->second) == attribIt->second; break; 399 case EGL_RECORDABLE_ANDROID: match = config->mRecordableAndroid == (EGLBoolean)attribIt->second; break; 400 case EGL_FRAMEBUFFER_TARGET_ANDROID: match = config->mFramebufferTargetAndroid == (EGLBoolean)attribIt->second; break; 401 402 // Ignored attributes 403 case EGL_MAX_PBUFFER_WIDTH: 404 case EGL_MAX_PBUFFER_HEIGHT: 405 case EGL_MAX_PBUFFER_PIXELS: 406 case EGL_NATIVE_VISUAL_ID: 407 break; 408 409 default: 410 *numConfig = 0; 411 return false; 412 } 413 414 if(!match) 415 { 416 break; 417 } 418 } 419 420 if(attribIt->first == EGL_CONFIG_CAVEAT) 421 { 422 caveatMatch = match; 423 } 424 } 425 426 if(match && caveatMatch) // We require the caveats to be NONE or the requested flags 427 { 428 passed.push_back(&*config); 429 } 430 } 431 432 if(configs) 433 { 434 sort(passed.begin(), passed.end(), SortConfig(attribList)); 435 436 EGLint index; 437 for(index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++) 438 { 439 configs[index] = passed[index]->getHandle(); 440 } 441 442 *numConfig = index; 443 } 444 else 445 { 446 *numConfig = static_cast<EGLint>(passed.size()); 447 } 448 449 return true; 450 } 451 452 const egl::Config *ConfigSet::get(EGLConfig configHandle) 453 { 454 for(Iterator config = mSet.begin(); config != mSet.end(); config++) 455 { 456 if(config->getHandle() == configHandle) 457 { 458 return &(*config); 459 } 460 } 461 462 return nullptr; 463 } 464 } 465