blob: e4dc704a997488a6c4c77370c9008dcf61f23681 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libEGL/Config.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
13#include <algorithm>
14#include <vector>
15
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000016#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000017
18using namespace std;
19
20namespace egl
21{
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +000022Config::Config(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023 : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample)
24{
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +000025 set(displayMode, minInterval, maxInterval, renderTargetFormat, depthStencilFormat, multiSample, texWidth, texHeight);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000026}
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
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +000065void Config::set(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000066{
jbauman@chromium.orgae345802011-03-30 22:04:25 +000067 mBindToTextureRGB = EGL_FALSE;
68 mBindToTextureRGBA = EGL_FALSE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000069 switch (renderTargetFormat)
70 {
71 case D3DFMT_A1R5G5B5:
72 mBufferSize = 16;
73 mRedSize = 5;
74 mGreenSize = 5;
75 mBlueSize = 5;
76 mAlphaSize = 1;
77 break;
78 case D3DFMT_A2R10G10B10:
79 mBufferSize = 32;
80 mRedSize = 10;
81 mGreenSize = 10;
82 mBlueSize = 10;
83 mAlphaSize = 2;
84 break;
85 case D3DFMT_A8R8G8B8:
86 mBufferSize = 32;
87 mRedSize = 8;
88 mGreenSize = 8;
89 mBlueSize = 8;
90 mAlphaSize = 8;
jbauman@chromium.orgae345802011-03-30 22:04:25 +000091 mBindToTextureRGBA = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000092 break;
93 case D3DFMT_R5G6B5:
94 mBufferSize = 16;
95 mRedSize = 5;
96 mGreenSize = 6;
97 mBlueSize = 5;
98 mAlphaSize = 0;
99 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100 case D3DFMT_X8R8G8B8:
101 mBufferSize = 32;
102 mRedSize = 8;
103 mGreenSize = 8;
104 mBlueSize = 8;
105 mAlphaSize = 0;
jbauman@chromium.orgae345802011-03-30 22:04:25 +0000106 mBindToTextureRGB = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000107 break;
108 default:
109 UNREACHABLE(); // Other formats should not be valid
110 }
111
112 mLuminanceSize = 0;
113 mAlphaMaskSize = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000114 mColorBufferType = EGL_RGB_BUFFER;
daniel@transgaming.com73248ec2010-05-12 03:40:40 +0000115 mConfigCaveat = (displayMode.Format == renderTargetFormat) ? EGL_NONE : EGL_SLOW_CONFIG;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000116 mConfigID = 0;
117 mConformant = EGL_OPENGL_ES2_BIT;
118
119 switch (depthStencilFormat)
120 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000121 case D3DFMT_UNKNOWN:
122 mDepthSize = 0;
123 mStencilSize = 0;
124 break;
daniel@transgaming.comd091b192010-05-07 19:01:47 +0000125// case D3DFMT_D16_LOCKABLE:
126// mDepthSize = 16;
127// mStencilSize = 0;
128// break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000129 case D3DFMT_D32:
130 mDepthSize = 32;
131 mStencilSize = 0;
132 break;
133 case D3DFMT_D15S1:
daniel@transgaming.comc28e76b2010-05-05 18:47:16 +0000134 mDepthSize = 15;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135 mStencilSize = 1;
136 break;
137 case D3DFMT_D24S8:
138 mDepthSize = 24;
139 mStencilSize = 8;
140 break;
141 case D3DFMT_D24X8:
142 mDepthSize = 24;
143 mStencilSize = 0;
144 break;
145 case D3DFMT_D24X4S4:
146 mDepthSize = 24;
147 mStencilSize = 4;
148 break;
149 case D3DFMT_D16:
150 mDepthSize = 16;
151 mStencilSize = 0;
152 break;
153// case D3DFMT_D32F_LOCKABLE:
daniel@transgaming.comd091b192010-05-07 19:01:47 +0000154// mDepthSize = 32;
155// mStencilSize = 0;
156// break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157// case D3DFMT_D24FS8:
daniel@transgaming.comd091b192010-05-07 19:01:47 +0000158// mDepthSize = 24;
159// mStencilSize = 8;
160// break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161 default:
162 UNREACHABLE();
163 }
164
165 mLevel = 0;
166 mMatchNativePixmap = EGL_NONE;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000167 mMaxPBufferWidth = texWidth;
168 mMaxPBufferHeight = texHeight;
169 mMaxPBufferPixels = texWidth*texHeight;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170 mMaxSwapInterval = maxInterval;
171 mMinSwapInterval = minInterval;
172 mNativeRenderable = EGL_FALSE;
173 mNativeVisualID = 0;
174 mNativeVisualType = 0;
175 mRenderableType = EGL_OPENGL_ES2_BIT;
176 mSampleBuffers = multiSample ? 1 : 0;
177 mSamples = multiSample;
178 mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
179 mTransparentType = EGL_NONE;
180 mTransparentRedValue = 0;
181 mTransparentGreenValue = 0;
182 mTransparentBlueValue = 0;
183}
184
185EGLConfig Config::getHandle() const
186{
187 return (EGLConfig)(size_t)mConfigID;
188}
189
190SortConfig::SortConfig(const EGLint *attribList)
191 : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
192{
193 scanForWantedComponents(attribList);
194}
195
196void SortConfig::scanForWantedComponents(const EGLint *attribList)
197{
198 // [EGL] section 3.4.1 page 24
199 // Sorting rule #3: by larger total number of color bits, not considering
200 // components that are 0 or don't-care.
201 for (const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
202 {
203 if (attr[1] != 0 && attr[1] != EGL_DONT_CARE)
204 {
205 switch (attr[0])
206 {
207 case EGL_RED_SIZE: mWantRed = true; break;
208 case EGL_GREEN_SIZE: mWantGreen = true; break;
209 case EGL_BLUE_SIZE: mWantBlue = true; break;
210 case EGL_ALPHA_SIZE: mWantAlpha = true; break;
211 case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
212 }
213 }
214 }
215}
216
217EGLint SortConfig::wantedComponentsSize(const Config &config) const
218{
219 EGLint total = 0;
220
221 if (mWantRed) total += config.mRedSize;
222 if (mWantGreen) total += config.mGreenSize;
223 if (mWantBlue) total += config.mBlueSize;
224 if (mWantAlpha) total += config.mAlphaSize;
225 if (mWantLuminance) total += config.mLuminanceSize;
226
227 return total;
228}
229
230bool SortConfig::operator()(const Config *x, const Config *y) const
231{
232 return (*this)(*x, *y);
233}
234
235bool SortConfig::operator()(const Config &x, const Config &y) const
236{
237 #define SORT(attribute) \
238 if (x.attribute != y.attribute) \
239 { \
240 return x.attribute < y.attribute; \
241 }
242
243 META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
244 SORT(mConfigCaveat);
245
246 META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
247 SORT(mColorBufferType);
248
249 // By larger total number of color bits, only considering those that are requested to be > 0.
250 EGLint xComponentsSize = wantedComponentsSize(x);
251 EGLint yComponentsSize = wantedComponentsSize(y);
252 if (xComponentsSize != yComponentsSize)
253 {
254 return xComponentsSize > yComponentsSize;
255 }
256
257 SORT(mBufferSize);
258 SORT(mSampleBuffers);
259 SORT(mSamples);
260 SORT(mDepthSize);
261 SORT(mStencilSize);
262 SORT(mAlphaMaskSize);
263 SORT(mNativeVisualType);
264 SORT(mConfigID);
265
266 #undef SORT
267
268 return false;
269}
270
271// We'd like to use SortConfig to also eliminate duplicate configs.
272// This works as long as we never have two configs with different per-RGB-component layouts,
273// but the same total.
274// 5551 and 565 are different because R+G+B is different.
275// 5551 and 555 are different because bufferSize is different.
276const EGLint ConfigSet::mSortAttribs[] =
277{
278 EGL_RED_SIZE, 1,
279 EGL_GREEN_SIZE, 1,
280 EGL_BLUE_SIZE, 1,
281 EGL_LUMINANCE_SIZE, 1,
282 // BUT NOT ALPHA
283 EGL_NONE
284};
285
286ConfigSet::ConfigSet()
287 : mSet(SortConfig(mSortAttribs))
288{
289}
290
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000291void ConfigSet::add(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292{
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000293 Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample, texWidth, texHeight);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294
295 mSet.insert(config);
296}
297
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298size_t ConfigSet::size() const
299{
300 return mSet.size();
301}
302
303bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
304{
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000305 vector<const Config*> passed;
306 passed.reserve(mSet.size());
307
308 for (Iterator config = mSet.begin(); config != mSet.end(); config++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309 {
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000310 bool match = true;
311 const EGLint *attribute = attribList;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000312
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000313 while (attribute[0] != EGL_NONE)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000314 {
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000315 switch (attribute[0])
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316 {
daniel@transgaming.com178adff2010-05-18 18:52:04 +0000317 case EGL_BUFFER_SIZE: match = config->mBufferSize >= attribute[1]; break;
318 case EGL_ALPHA_SIZE: match = config->mAlphaSize >= attribute[1]; break;
319 case EGL_BLUE_SIZE: match = config->mBlueSize >= attribute[1]; break;
320 case EGL_GREEN_SIZE: match = config->mGreenSize >= attribute[1]; break;
321 case EGL_RED_SIZE: match = config->mRedSize >= attribute[1]; break;
322 case EGL_DEPTH_SIZE: match = config->mDepthSize >= attribute[1]; break;
323 case EGL_STENCIL_SIZE: match = config->mStencilSize >= attribute[1]; break;
324 case EGL_CONFIG_CAVEAT: match = config->mConfigCaveat == attribute[1]; break;
325 case EGL_CONFIG_ID: match = config->mConfigID == attribute[1]; break;
326 case EGL_LEVEL: match = config->mLevel >= attribute[1]; break;
327 case EGL_NATIVE_RENDERABLE: match = config->mNativeRenderable == attribute[1]; break;
328 case EGL_NATIVE_VISUAL_TYPE: match = config->mNativeVisualType == attribute[1]; break;
329 case EGL_SAMPLES: match = config->mSamples >= attribute[1]; break;
330 case EGL_SAMPLE_BUFFERS: match = config->mSampleBuffers >= attribute[1]; break;
331 case EGL_SURFACE_TYPE: match = (config->mSurfaceType & attribute[1]) == attribute[1]; break;
332 case EGL_TRANSPARENT_TYPE: match = config->mTransparentType == attribute[1]; break;
333 case EGL_TRANSPARENT_BLUE_VALUE: match = config->mTransparentBlueValue == attribute[1]; break;
334 case EGL_TRANSPARENT_GREEN_VALUE: match = config->mTransparentGreenValue == attribute[1]; break;
335 case EGL_TRANSPARENT_RED_VALUE: match = config->mTransparentRedValue == attribute[1]; break;
336 case EGL_BIND_TO_TEXTURE_RGB: match = config->mBindToTextureRGB == attribute[1]; break;
337 case EGL_BIND_TO_TEXTURE_RGBA: match = config->mBindToTextureRGBA == attribute[1]; break;
338 case EGL_MIN_SWAP_INTERVAL: match = config->mMinSwapInterval == attribute[1]; break;
339 case EGL_MAX_SWAP_INTERVAL: match = config->mMaxSwapInterval == attribute[1]; break;
340 case EGL_LUMINANCE_SIZE: match = config->mLuminanceSize >= attribute[1]; break;
341 case EGL_ALPHA_MASK_SIZE: match = config->mAlphaMaskSize >= attribute[1]; break;
342 case EGL_COLOR_BUFFER_TYPE: match = config->mColorBufferType == attribute[1]; break;
343 case EGL_RENDERABLE_TYPE: match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
344 case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break;
345 case EGL_CONFORMANT: match = (config->mConformant & attribute[1]) == attribute[1]; break;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000346 case EGL_MAX_PBUFFER_WIDTH: match = config->mMaxPBufferWidth >= attribute[1]; break;
347 case EGL_MAX_PBUFFER_HEIGHT: match = config->mMaxPBufferHeight >= attribute[1]; break;
348 case EGL_MAX_PBUFFER_PIXELS: match = config->mMaxPBufferPixels >= attribute[1]; break;
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000349 default:
350 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351 }
352
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000353 if (!match)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354 {
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000355 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000356 }
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000357
358 attribute += 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359 }
360
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000361 if (match)
362 {
363 passed.push_back(&*config);
364 }
365 }
366
367 if (configs)
368 {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000369 sort(passed.begin(), passed.end(), SortConfig(attribList));
370
371 EGLint index;
372 for (index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
373 {
374 configs[index] = passed[index]->getHandle();
375 }
376
377 *numConfig = index;
378 }
379 else
380 {
daniel@transgaming.com6a94b972010-05-13 02:02:34 +0000381 *numConfig = passed.size();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000382 }
383
384 return true;
385}
386
387const egl::Config *ConfigSet::get(EGLConfig configHandle)
388{
389 for (Iterator config = mSet.begin(); config != mSet.end(); config++)
390 {
391 if (config->getHandle() == configHandle)
392 {
393 return &(*config);
394 }
395 }
396
397 return NULL;
398}
399}