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