1//
2// Copyright (c) 2002-2010 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.4] section 3.4 page 15.
10
11#include "libEGL/Config.h"
12
13#include <algorithm>
14#include <vector>
15
16#include "angle_gl.h"
17#include <EGL/eglext.h>
18
19#include "common/debug.h"
20
21using namespace std;
22
23namespace egl
24{
25Config::Config(rx::ConfigDesc desc, EGLint minInterval, EGLint maxInterval, EGLint texWidth, EGLint texHeight)
26    : mRenderTargetFormat(desc.renderTargetFormat), mDepthStencilFormat(desc.depthStencilFormat), mMultiSample(desc.multiSample)
27{
28    mBindToTextureRGB = EGL_FALSE;
29    mBindToTextureRGBA = EGL_FALSE;
30    switch (desc.renderTargetFormat)
31    {
32      case GL_RGB5_A1:
33        mBufferSize = 16;
34        mRedSize = 5;
35        mGreenSize = 5;
36        mBlueSize = 5;
37        mAlphaSize = 1;
38        break;
39      case GL_BGR5_A1_ANGLEX:
40        mBufferSize = 16;
41        mRedSize = 5;
42        mGreenSize = 5;
43        mBlueSize = 5;
44        mAlphaSize = 1;
45        break;
46      case GL_RGBA8_OES:
47        mBufferSize = 32;
48        mRedSize = 8;
49        mGreenSize = 8;
50        mBlueSize = 8;
51        mAlphaSize = 8;
52        mBindToTextureRGBA = true;
53        break;
54      case GL_RGB565:
55        mBufferSize = 16;
56        mRedSize = 5;
57        mGreenSize = 6;
58        mBlueSize = 5;
59        mAlphaSize = 0;
60        break;
61      case GL_RGB8_OES:
62        mBufferSize = 32;
63        mRedSize = 8;
64        mGreenSize = 8;
65        mBlueSize = 8;
66        mAlphaSize = 0;
67        mBindToTextureRGB = true;
68        break;
69      case GL_BGRA8_EXT:
70        mBufferSize = 32;
71        mRedSize = 8;
72        mGreenSize = 8;
73        mBlueSize = 8;
74        mAlphaSize = 8;
75        mBindToTextureRGBA = true;
76        break;
77      default:
78        UNREACHABLE();   // Other formats should not be valid
79    }
80
81    mLuminanceSize = 0;
82    mAlphaMaskSize = 0;
83    mColorBufferType = EGL_RGB_BUFFER;
84    mConfigCaveat = (desc.fastConfig) ? EGL_NONE : EGL_SLOW_CONFIG;
85    mConfigID = 0;
86    mConformant = EGL_OPENGL_ES2_BIT;
87
88    switch (desc.depthStencilFormat)
89    {
90      case GL_NONE:
91        mDepthSize = 0;
92        mStencilSize = 0;
93        break;
94      case GL_DEPTH_COMPONENT32_OES:
95        mDepthSize = 32;
96        mStencilSize = 0;
97        break;
98      case GL_DEPTH24_STENCIL8_OES:
99        mDepthSize = 24;
100        mStencilSize = 8;
101        break;
102      case GL_DEPTH_COMPONENT24_OES:
103        mDepthSize = 24;
104        mStencilSize = 0;
105        break;
106      case GL_DEPTH_COMPONENT16:
107        mDepthSize = 16;
108        mStencilSize = 0;
109        break;
110      default:
111        UNREACHABLE();
112    }
113
114    mLevel = 0;
115    mMatchNativePixmap = EGL_NONE;
116    mMaxPBufferWidth = texWidth;
117    mMaxPBufferHeight = texHeight;
118    mMaxPBufferPixels = texWidth*texHeight;
119    mMaxSwapInterval = maxInterval;
120    mMinSwapInterval = minInterval;
121    mNativeRenderable = EGL_FALSE;
122    mNativeVisualID = 0;
123    mNativeVisualType = 0;
124    mRenderableType = EGL_OPENGL_ES2_BIT;
125    mSampleBuffers = desc.multiSample ? 1 : 0;
126    mSamples = desc.multiSample;
127    mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
128    mTransparentType = EGL_NONE;
129    mTransparentRedValue = 0;
130    mTransparentGreenValue = 0;
131    mTransparentBlueValue = 0;
132
133    if (desc.es3Capable)
134    {
135        mRenderableType |= EGL_OPENGL_ES3_BIT_KHR;
136        mConformant |= EGL_OPENGL_ES3_BIT_KHR;
137    }
138}
139
140EGLConfig Config::getHandle() const
141{
142    return (EGLConfig)(size_t)mConfigID;
143}
144
145SortConfig::SortConfig(const EGLint *attribList)
146    : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
147{
148    scanForWantedComponents(attribList);
149}
150
151void SortConfig::scanForWantedComponents(const EGLint *attribList)
152{
153    // [EGL] section 3.4.1 page 24
154    // Sorting rule #3: by larger total number of color bits, not considering
155    // components that are 0 or don't-care.
156    for (const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
157    {
158        if (attr[1] != 0 && attr[1] != EGL_DONT_CARE)
159        {
160            switch (attr[0])
161            {
162              case EGL_RED_SIZE:       mWantRed = true; break;
163              case EGL_GREEN_SIZE:     mWantGreen = true; break;
164              case EGL_BLUE_SIZE:      mWantBlue = true; break;
165              case EGL_ALPHA_SIZE:     mWantAlpha = true; break;
166              case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
167            }
168        }
169    }
170}
171
172EGLint SortConfig::wantedComponentsSize(const Config &config) const
173{
174    EGLint total = 0;
175
176    if (mWantRed)       total += config.mRedSize;
177    if (mWantGreen)     total += config.mGreenSize;
178    if (mWantBlue)      total += config.mBlueSize;
179    if (mWantAlpha)     total += config.mAlphaSize;
180    if (mWantLuminance) total += config.mLuminanceSize;
181
182    return total;
183}
184
185bool SortConfig::operator()(const Config *x, const Config *y) const
186{
187    return (*this)(*x, *y);
188}
189
190bool SortConfig::operator()(const Config &x, const Config &y) const
191{
192    #define SORT(attribute)                        \
193        if (x.attribute != y.attribute)            \
194        {                                          \
195            return x.attribute < y.attribute;      \
196        }
197
198    META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
199    SORT(mConfigCaveat);
200
201    META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
202    SORT(mColorBufferType);
203
204    // By larger total number of color bits, only considering those that are requested to be > 0.
205    EGLint xComponentsSize = wantedComponentsSize(x);
206    EGLint yComponentsSize = wantedComponentsSize(y);
207    if (xComponentsSize != yComponentsSize)
208    {
209        return xComponentsSize > yComponentsSize;
210    }
211
212    SORT(mBufferSize);
213    SORT(mSampleBuffers);
214    SORT(mSamples);
215    SORT(mDepthSize);
216    SORT(mStencilSize);
217    SORT(mAlphaMaskSize);
218    SORT(mNativeVisualType);
219    SORT(mConfigID);
220
221    #undef SORT
222
223    return false;
224}
225
226// We'd like to use SortConfig to also eliminate duplicate configs.
227// This works as long as we never have two configs with different per-RGB-component layouts,
228// but the same total.
229// 5551 and 565 are different because R+G+B is different.
230// 5551 and 555 are different because bufferSize is different.
231const EGLint ConfigSet::mSortAttribs[] =
232{
233    EGL_RED_SIZE, 1,
234    EGL_GREEN_SIZE, 1,
235    EGL_BLUE_SIZE, 1,
236    EGL_LUMINANCE_SIZE, 1,
237    // BUT NOT ALPHA
238    EGL_NONE
239};
240
241ConfigSet::ConfigSet()
242    : mSet(SortConfig(mSortAttribs))
243{
244}
245
246void ConfigSet::add(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, EGLint texWidth, EGLint texHeight)
247{
248    Config config(desc, minSwapInterval, maxSwapInterval, texWidth, texHeight);
249    mSet.insert(config);
250}
251
252size_t ConfigSet::size() const
253{
254    return mSet.size();
255}
256
257bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
258{
259    vector<const Config*> passed;
260    passed.reserve(mSet.size());
261
262    for (Iterator config = mSet.begin(); config != mSet.end(); config++)
263    {
264        bool match = true;
265        const EGLint *attribute = attribList;
266
267        while (attribute[0] != EGL_NONE)
268        {
269            switch (attribute[0])
270            {
271              case EGL_BUFFER_SIZE:               match = config->mBufferSize >= attribute[1];                      break;
272              case EGL_ALPHA_SIZE:                match = config->mAlphaSize >= attribute[1];                       break;
273              case EGL_BLUE_SIZE:                 match = config->mBlueSize >= attribute[1];                        break;
274              case EGL_GREEN_SIZE:                match = config->mGreenSize >= attribute[1];                       break;
275              case EGL_RED_SIZE:                  match = config->mRedSize >= attribute[1];                         break;
276              case EGL_DEPTH_SIZE:                match = config->mDepthSize >= attribute[1];                       break;
277              case EGL_STENCIL_SIZE:              match = config->mStencilSize >= attribute[1];                     break;
278              case EGL_CONFIG_CAVEAT:             match = config->mConfigCaveat == (EGLenum) attribute[1];          break;
279              case EGL_CONFIG_ID:                 match = config->mConfigID == attribute[1];                        break;
280              case EGL_LEVEL:                     match = config->mLevel >= attribute[1];                           break;
281              case EGL_NATIVE_RENDERABLE:         match = config->mNativeRenderable == (EGLBoolean) attribute[1];   break;
282              case EGL_NATIVE_VISUAL_TYPE:        match = config->mNativeVisualType == attribute[1];                break;
283              case EGL_SAMPLES:                   match = config->mSamples >= attribute[1];                         break;
284              case EGL_SAMPLE_BUFFERS:            match = config->mSampleBuffers >= attribute[1];                   break;
285              case EGL_SURFACE_TYPE:              match = (config->mSurfaceType & attribute[1]) == attribute[1];    break;
286              case EGL_TRANSPARENT_TYPE:          match = config->mTransparentType == (EGLenum) attribute[1];       break;
287              case EGL_TRANSPARENT_BLUE_VALUE:    match = config->mTransparentBlueValue == attribute[1];            break;
288              case EGL_TRANSPARENT_GREEN_VALUE:   match = config->mTransparentGreenValue == attribute[1];           break;
289              case EGL_TRANSPARENT_RED_VALUE:     match = config->mTransparentRedValue == attribute[1];             break;
290              case EGL_BIND_TO_TEXTURE_RGB:       match = config->mBindToTextureRGB == (EGLBoolean) attribute[1];   break;
291              case EGL_BIND_TO_TEXTURE_RGBA:      match = config->mBindToTextureRGBA == (EGLBoolean) attribute[1];  break;
292              case EGL_MIN_SWAP_INTERVAL:         match = config->mMinSwapInterval == attribute[1];                 break;
293              case EGL_MAX_SWAP_INTERVAL:         match = config->mMaxSwapInterval == attribute[1];                 break;
294              case EGL_LUMINANCE_SIZE:            match = config->mLuminanceSize >= attribute[1];                   break;
295              case EGL_ALPHA_MASK_SIZE:           match = config->mAlphaMaskSize >= attribute[1];                   break;
296              case EGL_COLOR_BUFFER_TYPE:         match = config->mColorBufferType == (EGLenum) attribute[1];       break;
297              case EGL_RENDERABLE_TYPE:           match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
298              case EGL_MATCH_NATIVE_PIXMAP:       match = false; UNIMPLEMENTED();                                   break;
299              case EGL_CONFORMANT:                match = (config->mConformant & attribute[1]) == attribute[1];     break;
300              case EGL_MAX_PBUFFER_WIDTH:         match = config->mMaxPBufferWidth >= attribute[1];                 break;
301              case EGL_MAX_PBUFFER_HEIGHT:        match = config->mMaxPBufferHeight >= attribute[1];                break;
302              case EGL_MAX_PBUFFER_PIXELS:        match = config->mMaxPBufferPixels >= attribute[1];                break;
303              default:
304                return false;
305            }
306
307            if (!match)
308            {
309                break;
310            }
311
312            attribute += 2;
313        }
314
315        if (match)
316        {
317            passed.push_back(&*config);
318        }
319    }
320
321    if (configs)
322    {
323        sort(passed.begin(), passed.end(), SortConfig(attribList));
324
325        EGLint index;
326        for (index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
327        {
328            configs[index] = passed[index]->getHandle();
329        }
330
331        *numConfig = index;
332    }
333    else
334    {
335        *numConfig = passed.size();
336    }
337
338    return true;
339}
340
341const egl::Config *ConfigSet::get(EGLConfig configHandle)
342{
343    for (Iterator config = mSet.begin(); config != mSet.end(); config++)
344    {
345        if (config->getHandle() == configHandle)
346        {
347            return &(*config);
348        }
349    }
350
351    return NULL;
352}
353}
354