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