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