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