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 | |