1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // Config.cpp: Implements the egl::Config class, describing the format, type
8 // and size for an egl::Surface. Implements EGLConfig and related functionality.
9 // [EGL 1.5] section 3.4 page 19.
10 
11 #include "libANGLE/Config.h"
12 #include "libANGLE/AttributeMap.h"
13 
14 #include <algorithm>
15 #include <vector>
16 
17 #include <EGL/eglext.h>
18 #include "angle_gl.h"
19 
20 #include "common/debug.h"
21 
22 namespace egl
23 {
24 
Config()25 Config::Config()
26     : renderTargetFormat(GL_NONE),
27       depthStencilFormat(GL_NONE),
28       bufferSize(0),
29       redSize(0),
30       greenSize(0),
31       blueSize(0),
32       luminanceSize(0),
33       alphaSize(0),
34       alphaMaskSize(0),
35       bindToTextureRGB(EGL_FALSE),
36       bindToTextureRGBA(EGL_FALSE),
37       bindToTextureTarget(EGL_TEXTURE_2D),
38       colorBufferType(EGL_RGB_BUFFER),
39       configCaveat(EGL_NONE),
40       configID(0),
41       conformant(0),
42       depthSize(0),
43       level(0),
44       matchNativePixmap(EGL_FALSE),
45       maxPBufferWidth(0),
46       maxPBufferHeight(0),
47       maxPBufferPixels(0),
48       maxSwapInterval(0),
49       minSwapInterval(0),
50       nativeRenderable(EGL_FALSE),
51       nativeVisualID(0),
52       nativeVisualType(0),
53       renderableType(0),
54       sampleBuffers(0),
55       samples(0),
56       stencilSize(0),
57       surfaceType(0),
58       transparentType(EGL_NONE),
59       transparentRedValue(0),
60       transparentGreenValue(0),
61       transparentBlueValue(0),
62       optimalOrientation(0),
63       colorComponentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT),
64       recordable(EGL_FALSE),
65       framebufferTarget(EGL_FALSE),  // TODO: http://anglebug.com/4208
66       yInverted(EGL_FALSE)
67 {}
68 
~Config()69 Config::~Config() {}
70 
71 Config::Config(const Config &other) = default;
72 
73 Config &Config::operator=(const Config &other) = default;
74 
75 ConfigSet::ConfigSet() = default;
76 
77 ConfigSet::ConfigSet(const ConfigSet &other) = default;
78 
79 ConfigSet &ConfigSet::operator=(const ConfigSet &other) = default;
80 
81 ConfigSet::~ConfigSet() = default;
82 
add(const Config & config)83 EGLint ConfigSet::add(const Config &config)
84 {
85     // Set the config's ID to a small number that starts at 1 ([EGL 1.5] section 3.4)
86     EGLint id = static_cast<EGLint>(mConfigs.size()) + 1;
87 
88     Config copyConfig(config);
89     copyConfig.configID = id;
90     mConfigs.insert(std::make_pair(id, copyConfig));
91 
92     return id;
93 }
94 
get(EGLint id) const95 const Config &ConfigSet::get(EGLint id) const
96 {
97     ASSERT(mConfigs.find(id) != mConfigs.end());
98     return mConfigs.find(id)->second;
99 }
100 
clear()101 void ConfigSet::clear()
102 {
103     mConfigs.clear();
104 }
105 
size() const106 size_t ConfigSet::size() const
107 {
108     return mConfigs.size();
109 }
110 
contains(const Config * config) const111 bool ConfigSet::contains(const Config *config) const
112 {
113     for (auto i = mConfigs.begin(); i != mConfigs.end(); i++)
114     {
115         const Config &item = i->second;
116         if (config == &item)
117         {
118             return true;
119         }
120     }
121 
122     return false;
123 }
124 
125 // Function object used by STL sorting routines for ordering Configs according to [EGL 1.5]
126 // section 3.4.1.2 page 28.
127 class ConfigSorter
128 {
129   public:
ConfigSorter(const AttributeMap & attributeMap)130     explicit ConfigSorter(const AttributeMap &attributeMap)
131         : mWantRed(false),
132           mWantGreen(false),
133           mWantBlue(false),
134           mWantAlpha(false),
135           mWantLuminance(false)
136     {
137         scanForWantedComponents(attributeMap);
138     }
139 
operator ()(const Config * x,const Config * y) const140     bool operator()(const Config *x, const Config *y) const { return (*this)(*x, *y); }
141 
operator ()(const Config & x,const Config & y) const142     bool operator()(const Config &x, const Config &y) const
143     {
144 #define SORT(attribute)                       \
145     do                                        \
146     {                                         \
147         if (x.attribute != y.attribute)       \
148             return x.attribute < y.attribute; \
149     } while (0)
150 
151         static_assert(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG,
152                       "Unexpected EGL enum value.");
153         SORT(configCaveat);
154 
155         static_assert(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT < EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
156                       "Unexpected order of EGL enums.");
157         SORT(colorComponentType);
158 
159         static_assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER, "Unexpected EGL enum value.");
160         SORT(colorBufferType);
161 
162         // By larger total number of color bits, only considering those that are requested to be >
163         // 0.
164         EGLint xComponentsSize = wantedComponentsSize(x);
165         EGLint yComponentsSize = wantedComponentsSize(y);
166         if (xComponentsSize != yComponentsSize)
167         {
168             return xComponentsSize > yComponentsSize;
169         }
170 
171         SORT(bufferSize);
172         SORT(sampleBuffers);
173         SORT(samples);
174         SORT(depthSize);
175         SORT(stencilSize);
176         SORT(alphaMaskSize);
177         SORT(nativeVisualType);
178         SORT(configID);
179 
180 #undef SORT
181 
182         return false;
183     }
184 
185   private:
wantsComponent(const AttributeMap & attributeMap,EGLAttrib component)186     static bool wantsComponent(const AttributeMap &attributeMap, EGLAttrib component)
187     {
188         // [EGL 1.5] section 3.4.1.2 page 30
189         // Sorting rule #3: by larger total number of color bits, not considering
190         // components that are 0 or don't-care.
191         EGLAttrib value = attributeMap.get(component, 0);
192         return value != 0 && value != EGL_DONT_CARE;
193     }
194 
scanForWantedComponents(const AttributeMap & attributeMap)195     void scanForWantedComponents(const AttributeMap &attributeMap)
196     {
197         mWantRed       = wantsComponent(attributeMap, EGL_RED_SIZE);
198         mWantGreen     = wantsComponent(attributeMap, EGL_GREEN_SIZE);
199         mWantBlue      = wantsComponent(attributeMap, EGL_BLUE_SIZE);
200         mWantAlpha     = wantsComponent(attributeMap, EGL_ALPHA_SIZE);
201         mWantLuminance = wantsComponent(attributeMap, EGL_LUMINANCE_SIZE);
202     }
203 
wantedComponentsSize(const Config & config) const204     EGLint wantedComponentsSize(const Config &config) const
205     {
206         EGLint total = 0;
207 
208         if (mWantRed)
209             total += config.redSize;
210         if (mWantGreen)
211             total += config.greenSize;
212         if (mWantBlue)
213             total += config.blueSize;
214         if (mWantAlpha)
215             total += config.alphaSize;
216         if (mWantLuminance)
217             total += config.luminanceSize;
218 
219         return total;
220     }
221 
222     bool mWantRed;
223     bool mWantGreen;
224     bool mWantBlue;
225     bool mWantAlpha;
226     bool mWantLuminance;
227 };
228 
filter(const AttributeMap & attributeMap) const229 std::vector<const Config *> ConfigSet::filter(const AttributeMap &attributeMap) const
230 {
231     std::vector<const Config *> result;
232     result.reserve(mConfigs.size());
233 
234     for (auto configIter = mConfigs.begin(); configIter != mConfigs.end(); configIter++)
235     {
236         const Config &config = configIter->second;
237         bool match           = true;
238 
239         for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++)
240         {
241             EGLAttrib attributeKey   = attribIter->first;
242             EGLAttrib attributeValue = attribIter->second;
243 
244             if (attributeValue == EGL_DONT_CARE)
245             {
246                 continue;
247             }
248 
249             switch (attributeKey)
250             {
251                 case EGL_BUFFER_SIZE:
252                     match = config.bufferSize >= attributeValue;
253                     break;
254                 case EGL_ALPHA_SIZE:
255                     match = config.alphaSize >= attributeValue;
256                     break;
257                 case EGL_BLUE_SIZE:
258                     match = config.blueSize >= attributeValue;
259                     break;
260                 case EGL_GREEN_SIZE:
261                     match = config.greenSize >= attributeValue;
262                     break;
263                 case EGL_RED_SIZE:
264                     match = config.redSize >= attributeValue;
265                     break;
266                 case EGL_DEPTH_SIZE:
267                     match = config.depthSize >= attributeValue;
268                     break;
269                 case EGL_STENCIL_SIZE:
270                     match = config.stencilSize >= attributeValue;
271                     break;
272                 case EGL_CONFIG_CAVEAT:
273                     match = config.configCaveat == static_cast<EGLenum>(attributeValue);
274                     break;
275                 case EGL_CONFIG_ID:
276                     match = config.configID == attributeValue;
277                     break;
278                 case EGL_LEVEL:
279                     match = config.level == attributeValue;
280                     break;
281                 case EGL_NATIVE_RENDERABLE:
282                     match = config.nativeRenderable == static_cast<EGLBoolean>(attributeValue);
283                     break;
284                 case EGL_NATIVE_VISUAL_TYPE:
285                     match = config.nativeVisualType == attributeValue;
286                     break;
287                 case EGL_SAMPLES:
288                     match = config.samples >= attributeValue;
289                     break;
290                 case EGL_SAMPLE_BUFFERS:
291                     match = config.sampleBuffers >= attributeValue;
292                     break;
293                 case EGL_SURFACE_TYPE:
294                     match = (config.surfaceType & attributeValue) == attributeValue;
295                     break;
296                 case EGL_TRANSPARENT_TYPE:
297                     match = config.transparentType == static_cast<EGLenum>(attributeValue);
298                     break;
299                 case EGL_TRANSPARENT_BLUE_VALUE:
300                     if (attributeMap.get(EGL_TRANSPARENT_TYPE, EGL_NONE) != EGL_NONE)
301                     {
302                         match = config.transparentBlueValue == attributeValue;
303                     }
304                     break;
305                 case EGL_TRANSPARENT_GREEN_VALUE:
306                     if (attributeMap.get(EGL_TRANSPARENT_TYPE, EGL_NONE) != EGL_NONE)
307                     {
308                         match = config.transparentGreenValue == attributeValue;
309                     }
310                     break;
311                 case EGL_TRANSPARENT_RED_VALUE:
312                     if (attributeMap.get(EGL_TRANSPARENT_TYPE, EGL_NONE) != EGL_NONE)
313                     {
314                         match = config.transparentRedValue == attributeValue;
315                     }
316                     break;
317                 case EGL_BIND_TO_TEXTURE_RGB:
318                     match = config.bindToTextureRGB == static_cast<EGLBoolean>(attributeValue);
319                     break;
320                 case EGL_BIND_TO_TEXTURE_RGBA:
321                     match = config.bindToTextureRGBA == static_cast<EGLBoolean>(attributeValue);
322                     break;
323                 case EGL_BIND_TO_TEXTURE_TARGET_ANGLE:
324                     match = config.bindToTextureTarget == static_cast<EGLenum>(attributeValue);
325                     break;
326                 case EGL_MIN_SWAP_INTERVAL:
327                     match = config.minSwapInterval == attributeValue;
328                     break;
329                 case EGL_MAX_SWAP_INTERVAL:
330                     match = config.maxSwapInterval == attributeValue;
331                     break;
332                 case EGL_LUMINANCE_SIZE:
333                     match = config.luminanceSize >= attributeValue;
334                     break;
335                 case EGL_ALPHA_MASK_SIZE:
336                     match = config.alphaMaskSize >= attributeValue;
337                     break;
338                 case EGL_COLOR_BUFFER_TYPE:
339                     match = config.colorBufferType == static_cast<EGLenum>(attributeValue);
340                     break;
341                 case EGL_RENDERABLE_TYPE:
342                     match = (config.renderableType & attributeValue) == attributeValue;
343                     break;
344                 case EGL_MATCH_NATIVE_PIXMAP:
345                     match = false;
346                     UNIMPLEMENTED();
347                     break;
348                 case EGL_CONFORMANT:
349                     match = (config.conformant & attributeValue) == attributeValue;
350                     break;
351                 case EGL_MAX_PBUFFER_WIDTH:
352                     match = config.maxPBufferWidth >= attributeValue;
353                     break;
354                 case EGL_MAX_PBUFFER_HEIGHT:
355                     match = config.maxPBufferHeight >= attributeValue;
356                     break;
357                 case EGL_MAX_PBUFFER_PIXELS:
358                     match = config.maxPBufferPixels >= attributeValue;
359                     break;
360                 case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
361                     match = config.optimalOrientation == attributeValue;
362                     break;
363                 case EGL_COLOR_COMPONENT_TYPE_EXT:
364                     match = config.colorComponentType == static_cast<EGLenum>(attributeValue);
365                     break;
366                 case EGL_RECORDABLE_ANDROID:
367                     match = config.recordable == static_cast<EGLBoolean>(attributeValue);
368                     break;
369                 case EGL_FRAMEBUFFER_TARGET_ANDROID:
370                     match = config.framebufferTarget == static_cast<EGLBoolean>(attributeValue);
371                     break;
372                 case EGL_Y_INVERTED_NOK:
373                     match = config.yInverted == static_cast<EGLBoolean>(attributeValue);
374                     break;
375                 default:
376                     UNREACHABLE();
377             }
378 
379             if (!match)
380             {
381                 break;
382             }
383         }
384 
385         if (match)
386         {
387             result.push_back(&config);
388         }
389     }
390 
391     // Sort the result
392     std::sort(result.begin(), result.end(), ConfigSorter(attributeMap));
393 
394     return result;
395 }
396 
begin()397 ConfigSet::ConfigMap::iterator ConfigSet::begin()
398 {
399     return mConfigs.begin();
400 }
401 
end()402 ConfigSet::ConfigMap::iterator ConfigSet::end()
403 {
404     return mConfigs.end();
405 }
406 }  // namespace egl
407