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