| 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 | #if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) | 
| 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 | 		#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) | 
| 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 | 		#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) | 
| 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 | 		#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) | 
| 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 | 		#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) | 
| 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 | 		#if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) | 
| 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 |  |