blob: 02d2e307fa212efb6109ec8b2da21d50a51fdc6e [file] [log] [blame]
daniel@transgaming.come979ead2010-09-23 18:03:14 +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// Display.cpp: Implements the egl::Display class, representing the abstract
8// display on which graphics are drawn. Implements EGLDisplay.
9// [EGL 1.4] section 2.1.2 page 3.
10
11#include "libEGL/Display.h"
12
13#include <algorithm>
14#include <vector>
15
16#include "common/debug.h"
jbauman@chromium.org06d7a752011-04-30 01:02:52 +000017#include "libGLESv2/mathutil.h"
daniel@transgaming.come979ead2010-09-23 18:03:14 +000018
19#include "libEGL/main.h"
20
21#define REF_RAST 0 // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
22#define ENABLE_D3D9EX 1 // Enables use of the IDirect3D9Ex interface, when available
23
24namespace egl
25{
26Display::Display(HDC deviceContext) : mDc(deviceContext)
27{
28 mD3d9Module = NULL;
29
30 mD3d9 = NULL;
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000031 mD3d9Ex = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +000032 mDevice = NULL;
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000033 mDeviceEx = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +000034 mDeviceWindow = NULL;
35
36 mAdapter = D3DADAPTER_DEFAULT;
37
38 #if REF_RAST == 1 || defined(FORCE_REF_RAST)
39 mDeviceType = D3DDEVTYPE_REF;
40 #else
41 mDeviceType = D3DDEVTYPE_HAL;
42 #endif
43
44 mMinSwapInterval = 1;
45 mMaxSwapInterval = 1;
46}
47
48Display::~Display()
49{
50 terminate();
51}
52
53bool Display::initialize()
54{
55 if (isInitialized())
56 {
57 return true;
58 }
59
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +000060 mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
daniel@transgaming.come979ead2010-09-23 18:03:14 +000061 if (mD3d9Module == NULL)
62 {
63 terminate();
64 return false;
65 }
66
daniel@transgaming.come979ead2010-09-23 18:03:14 +000067 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
68 Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
69
70 // Use Direct3D9Ex if available. Among other things, this version is less
71 // inclined to report a lost context, for example when the user switches
72 // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000073 if (ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
daniel@transgaming.come979ead2010-09-23 18:03:14 +000074 {
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000075 ASSERT(mD3d9Ex);
76 mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
daniel@transgaming.come979ead2010-09-23 18:03:14 +000077 ASSERT(mD3d9);
78 }
79 else
80 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +000081 mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
daniel@transgaming.come979ead2010-09-23 18:03:14 +000082 }
83
84 if (mD3d9)
85 {
86 if (mDc != NULL)
87 {
88 // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
89 }
90
91 HRESULT result;
92
apatrick@chromium.org1c768012010-10-07 00:35:24 +000093 // Give up on getting device caps after about one second.
94 for (int i = 0; i < 10; ++i)
daniel@transgaming.come979ead2010-09-23 18:03:14 +000095 {
96 result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
apatrick@chromium.org1c768012010-10-07 00:35:24 +000097
98 if (SUCCEEDED(result))
daniel@transgaming.come979ead2010-09-23 18:03:14 +000099 {
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000100 break;
101 }
102 else if (result == D3DERR_NOTAVAILABLE)
103 {
104 Sleep(100); // Give the driver some time to initialize/recover
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000105 }
106 else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
107 {
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000108 terminate();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000109 return error(EGL_BAD_ALLOC, false);
110 }
111 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000112
113 if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
114 {
115 terminate();
116 return error(EGL_NOT_INITIALIZED, false);
117 }
118
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000119 // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
120 // This is required by Texture2D::convertToRenderTarget.
121 if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
122 {
123 terminate();
124 return error(EGL_NOT_INITIALIZED, false);
125 }
126
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000127 mMinSwapInterval = 4;
128 mMaxSwapInterval = 0;
129
130 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {mMinSwapInterval = std::min(mMinSwapInterval, 0); mMaxSwapInterval = std::max(mMaxSwapInterval, 0);}
131 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) {mMinSwapInterval = std::min(mMinSwapInterval, 1); mMaxSwapInterval = std::max(mMaxSwapInterval, 1);}
132 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) {mMinSwapInterval = std::min(mMinSwapInterval, 2); mMaxSwapInterval = std::max(mMaxSwapInterval, 2);}
133 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);}
134 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);}
135
136 const D3DFORMAT renderTargetFormats[] =
137 {
138 D3DFMT_A1R5G5B5,
139 // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
140 D3DFMT_A8R8G8B8,
141 D3DFMT_R5G6B5,
daniel@transgaming.com73a5db62010-10-15 17:58:13 +0000142 // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000143 D3DFMT_X8R8G8B8
144 };
145
146 const D3DFORMAT depthStencilFormats[] =
147 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000148 D3DFMT_UNKNOWN,
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000149 // D3DFMT_D16_LOCKABLE,
150 D3DFMT_D32,
151 // D3DFMT_D15S1,
152 D3DFMT_D24S8,
153 D3DFMT_D24X8,
154 // D3DFMT_D24X4S4,
155 D3DFMT_D16,
156 // D3DFMT_D32F_LOCKABLE,
157 // D3DFMT_D24FS8
158 };
159
160 D3DDISPLAYMODE currentDisplayMode;
161 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
162
163 ConfigSet configSet;
164
165 for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++)
166 {
167 D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex];
168
169 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
170
171 if (SUCCEEDED(result))
172 {
173 for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++)
174 {
175 D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex];
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000176 HRESULT result = D3D_OK;
177
178 if(depthStencilFormat != D3DFMT_UNKNOWN)
179 {
180 result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
181 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000182
183 if (SUCCEEDED(result))
184 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000185 if(depthStencilFormat != D3DFMT_UNKNOWN)
186 {
187 result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
188 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000189
190 if (SUCCEEDED(result))
191 {
192 // FIXME: enumerate multi-sampling
193
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000194 configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0,
195 mDeviceCaps.MaxTextureWidth, mDeviceCaps.MaxTextureHeight);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000196 }
197 }
198 }
199 }
200 }
201
202 // Give the sorted configs a unique ID and store them internally
203 EGLint index = 1;
204 for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
205 {
206 Config configuration = *config;
207 configuration.mConfigID = index;
208 index++;
209
210 mConfigSet.mSet.insert(configuration);
211 }
212 }
213
214 if (!isInitialized())
215 {
216 terminate();
217
218 return false;
219 }
220
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000221 initExtensionString();
222
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000223 static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
224 static const TCHAR className[] = TEXT("STATIC");
225
226 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
227
228 return true;
229}
230
231void Display::terminate()
232{
233 while (!mSurfaceSet.empty())
234 {
235 destroySurface(*mSurfaceSet.begin());
236 }
237
238 while (!mContextSet.empty())
239 {
240 destroyContext(*mContextSet.begin());
241 }
242
243 if (mDevice)
244 {
245 // If the device is lost, reset it first to prevent leaving the driver in an unstable state
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000246 if (isDeviceLost())
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000247 {
248 resetDevice();
249 }
250
251 mDevice->Release();
252 mDevice = NULL;
253 }
254
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000255 if (mDeviceEx)
256 {
257 mDeviceEx->Release();
258 mDeviceEx = NULL;
259 }
260
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000261 if (mD3d9)
262 {
263 mD3d9->Release();
264 mD3d9 = NULL;
265 }
266
267 if (mDeviceWindow)
268 {
269 DestroyWindow(mDeviceWindow);
270 mDeviceWindow = NULL;
271 }
272
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000273 if (mD3d9Ex)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000274 {
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000275 mD3d9Ex->Release();
276 mD3d9Ex = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000277 }
278
279 if (mD3d9Module)
280 {
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000281 mD3d9Module = NULL;
282 }
283}
284
285void Display::startScene()
286{
287 if (!mSceneStarted)
288 {
289 long result = mDevice->BeginScene();
290 ASSERT(SUCCEEDED(result));
291 mSceneStarted = true;
292 }
293}
294
295void Display::endScene()
296{
297 if (mSceneStarted)
298 {
299 long result = mDevice->EndScene();
300 ASSERT(SUCCEEDED(result));
301 mSceneStarted = false;
302 }
303}
304
305bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
306{
307 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
308}
309
310bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
311{
312 const egl::Config *configuration = mConfigSet.get(config);
313
314 switch (attribute)
315 {
316 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
317 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
318 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
319 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
320 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
321 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
322 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
323 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
324 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
325 case EGL_LEVEL: *value = configuration->mLevel; break;
326 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
327 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
328 case EGL_SAMPLES: *value = configuration->mSamples; break;
329 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
330 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
331 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
332 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
333 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
334 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
335 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
336 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
337 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
338 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
339 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
340 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
341 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
342 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
343 case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
344 case EGL_CONFORMANT: *value = configuration->mConformant; break;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000345 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
346 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
347 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000348 default:
349 return false;
350 }
351
352 return true;
353}
354
355bool Display::createDevice()
356{
357 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
358 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
359
360 HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
361
362 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
363 {
364 return error(EGL_BAD_ALLOC, false);
365 }
366
367 if (FAILED(result))
368 {
369 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
370
371 if (FAILED(result))
372 {
373 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
374 return error(EGL_BAD_ALLOC, false);
375 }
376 }
377
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000378 if (mD3d9Ex)
379 {
380 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
381 ASSERT(SUCCEEDED(result));
382 }
383
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000384 // Permanent non-default states
385 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
386
387 mSceneStarted = false;
388
389 return true;
390}
391
392bool Display::resetDevice()
393{
394 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
395 HRESULT result;
396
397 do
398 {
399 Sleep(0); // Give the graphics driver some CPU time
400
401 result = mDevice->Reset(&presentParameters);
402 }
403 while (result == D3DERR_DEVICELOST);
404
405 if (FAILED(result))
406 {
407 return error(EGL_BAD_ALLOC, false);
408 }
409
410 ASSERT(SUCCEEDED(result));
411
412 return true;
413}
414
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000415EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000416{
417 const Config *configuration = mConfigSet.get(config);
418
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000419 if (attribList)
420 {
421 while (*attribList != EGL_NONE)
422 {
423 switch (attribList[0])
424 {
425 case EGL_RENDER_BUFFER:
426 switch (attribList[1])
427 {
428 case EGL_BACK_BUFFER:
429 break;
430 case EGL_SINGLE_BUFFER:
431 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
432 default:
433 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
434 }
435 break;
436 case EGL_VG_COLORSPACE:
437 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
438 case EGL_VG_ALPHA_FORMAT:
439 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
440 default:
441 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
442 }
443
444 attribList += 2;
445 }
446 }
447
448 if (hasExistingWindowSurface(window))
449 {
450 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
451 }
452
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000453 Surface *surface = new Surface(this, configuration, window);
454 mSurfaceSet.insert(surface);
455
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000456 return success(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000457}
458
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000459EGLSurface Display::createOffscreenSurface(EGLConfig config, const EGLint *attribList)
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000460{
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000461 EGLint width = 0, height = 0;
462 EGLenum textureFormat = EGL_NO_TEXTURE;
463 EGLenum textureTarget = EGL_NO_TEXTURE;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000464 const Config *configuration = mConfigSet.get(config);
465
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000466 if (attribList)
467 {
468 while (*attribList != EGL_NONE)
469 {
470 switch (attribList[0])
471 {
472 case EGL_WIDTH:
473 width = attribList[1];
474 break;
475 case EGL_HEIGHT:
476 height = attribList[1];
477 break;
478 case EGL_LARGEST_PBUFFER:
479 if (attribList[1] != EGL_FALSE)
480 UNIMPLEMENTED(); // FIXME
481 break;
482 case EGL_TEXTURE_FORMAT:
483 switch (attribList[1])
484 {
485 case EGL_NO_TEXTURE:
486 case EGL_TEXTURE_RGB:
487 case EGL_TEXTURE_RGBA:
488 textureFormat = attribList[1];
489 break;
490 default:
491 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
492 }
493 break;
494 case EGL_TEXTURE_TARGET:
495 switch (attribList[1])
496 {
497 case EGL_NO_TEXTURE:
498 case EGL_TEXTURE_2D:
499 textureTarget = attribList[1];
500 break;
501 default:
502 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
503 }
504 break;
505 case EGL_MIPMAP_TEXTURE:
506 if (attribList[1] != EGL_FALSE)
507 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
508 break;
509 case EGL_VG_COLORSPACE:
510 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
511 case EGL_VG_ALPHA_FORMAT:
512 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
513 default:
514 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
515 }
516
517 attribList += 2;
518 }
519 }
520
521 if (width < 0 || height < 0)
522 {
523 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
524 }
525
526 if (width == 0 || height == 0)
527 {
528 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
529 }
530
531 if (textureFormat != EGL_NO_TEXTURE && !getNonPow2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
532 {
533 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
534 }
535
536 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
537 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
538 {
539 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
540 }
541
542 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
543 {
544 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
545 }
546
547 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
548 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
549 {
550 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
551 }
552
jbauman@chromium.orgae345802011-03-30 22:04:25 +0000553 Surface *surface = new Surface(this, configuration, width, height, textureFormat, textureTarget);
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000554 mSurfaceSet.insert(surface);
555
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000556 return success(surface);
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000557}
558
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000559EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext)
560{
561 if (!mDevice)
562 {
563 if (!createDevice())
564 {
565 return NULL;
566 }
567 }
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000568 else if (isDeviceLost()) // Lost device
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000569 {
570 if (!resetDevice())
571 {
572 return NULL;
573 }
574
575 // Restore any surfaces that may have been lost
576 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
577 {
578 (*surface)->resetSwapChain();
579 }
580 }
581
582 const egl::Config *config = mConfigSet.get(configHandle);
583
584 gl::Context *context = glCreateContext(config, shareContext);
585 mContextSet.insert(context);
586
587 return context;
588}
589
590void Display::destroySurface(egl::Surface *surface)
591{
592 delete surface;
593 mSurfaceSet.erase(surface);
594}
595
596void Display::destroyContext(gl::Context *context)
597{
598 glDestroyContext(context);
599 mContextSet.erase(context);
600
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000601 if (mContextSet.empty() && mDevice && isDeviceLost()) // Last context of a lost device
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000602 {
603 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
604 {
605 (*surface)->release();
606 }
607 }
608}
609
610bool Display::isInitialized()
611{
612 return mD3d9 != NULL && mConfigSet.size() > 0;
613}
614
615bool Display::isValidConfig(EGLConfig config)
616{
617 return mConfigSet.get(config) != NULL;
618}
619
620bool Display::isValidContext(gl::Context *context)
621{
622 return mContextSet.find(context) != mContextSet.end();
623}
624
625bool Display::isValidSurface(egl::Surface *surface)
626{
627 return mSurfaceSet.find(surface) != mSurfaceSet.end();
628}
629
630bool Display::hasExistingWindowSurface(HWND window)
631{
632 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
633 {
634 if ((*surface)->getWindowHandle() == window)
635 {
636 return true;
637 }
638 }
639
640 return false;
641}
642
643EGLint Display::getMinSwapInterval()
644{
645 return mMinSwapInterval;
646}
647
648EGLint Display::getMaxSwapInterval()
649{
650 return mMaxSwapInterval;
651}
652
653IDirect3DDevice9 *Display::getDevice()
654{
655 if (!mDevice)
656 {
657 if (!createDevice())
658 {
659 return NULL;
660 }
661 }
662
663 return mDevice;
664}
665
666D3DCAPS9 Display::getDeviceCaps()
667{
668 return mDeviceCaps;
669}
670
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000671bool Display::isDeviceLost()
672{
673 if (mDeviceEx)
674 {
675 return FAILED(mDeviceEx->CheckDeviceState(NULL));
676 }
677 else
678 {
679 return FAILED(mDevice->TestCooperativeLevel());
680 }
681}
682
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000683void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
684{
685 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
686 {
687 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
688 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
689
690 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
691 }
692}
693
694bool Display::getCompressedTextureSupport()
695{
696 D3DDISPLAYMODE currentDisplayMode;
697 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
698
699 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
700}
701
702bool Display::getFloatTextureSupport(bool *filtering, bool *renderable)
703{
704 D3DDISPLAYMODE currentDisplayMode;
705 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
706
707 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
708 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
709 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
710 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
711
712 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
713 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
714 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
715 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
716
717 if (!filtering && !renderable)
718 {
719 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
720 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
721 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
722 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
723 }
724 else
725 {
726 return true;
727 }
728}
729
730bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable)
731{
732 D3DDISPLAYMODE currentDisplayMode;
733 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
734
735 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
736 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
737 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
738 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
739
740 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
741 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
742 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
743 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
744
745 if (!filtering && !renderable)
746 {
747 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
748 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
749 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
750 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
751 }
752 else
753 {
754 return true;
755 }
756}
757
daniel@transgaming.comed828e52010-10-15 17:57:30 +0000758bool Display::getLuminanceTextureSupport()
759{
760 D3DDISPLAYMODE currentDisplayMode;
761 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
762
763 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
764}
765
766bool Display::getLuminanceAlphaTextureSupport()
767{
768 D3DDISPLAYMODE currentDisplayMode;
769 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
770
771 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
772}
773
jbauman@chromium.orgae345802011-03-30 22:04:25 +0000774bool Display::getNonPow2TextureSupport()
775{
776 return !(mDeviceCaps.TextureCaps & (D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL));
777}
778
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000779D3DPOOL Display::getBufferPool(DWORD usage) const
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000780{
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000781 if (mD3d9Ex != NULL)
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000782 {
783 return D3DPOOL_DEFAULT;
784 }
785 else
786 {
787 if (!(usage & D3DUSAGE_DYNAMIC))
788 {
789 return D3DPOOL_MANAGED;
790 }
791 }
792
793 return D3DPOOL_DEFAULT;
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000794}
795
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000796bool Display::getEventQuerySupport()
797{
798 IDirect3DQuery9 *query;
799 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
800 if (SUCCEEDED(result))
801 {
802 query->Release();
803 }
804
805 return result != D3DERR_NOTAVAILABLE;
806}
807
808D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
809{
810 D3DPRESENT_PARAMETERS presentParameters = {0};
811
812 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
813 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
814 presentParameters.BackBufferCount = 1;
815 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
816 presentParameters.BackBufferWidth = 1;
817 presentParameters.BackBufferHeight = 1;
818 presentParameters.EnableAutoDepthStencil = FALSE;
819 presentParameters.Flags = 0;
820 presentParameters.hDeviceWindow = mDeviceWindow;
821 presentParameters.MultiSampleQuality = 0;
822 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
823 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
824 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
825 presentParameters.Windowed = TRUE;
826
827 return presentParameters;
828}
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000829
830void Display::initExtensionString()
831{
832 mExtensionString += "EGL_ANGLE_query_surface_pointer ";
833
834 if (isD3d9ExDevice()) {
835 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
836 }
837
838 std::string::size_type end = mExtensionString.find_last_not_of(' ');
839 if (end != std::string::npos)
840 {
841 mExtensionString.resize(end+1);
842 }
843}
844
845const char *Display::getExtensionString() const
846{
847 return mExtensionString.c_str();
848}
849
850}