Home | History | Annotate | Download | only in libEGL
      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