blob: 675097f3f1fdaebad1ee5b2f434581e88dfa6711 [file] [log] [blame]
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001//
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +00002// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.come979ead2010-09-23 18:03:14 +00003// 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);
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000454
455 if (!surface->initialize())
456 {
457 delete surface;
458 return EGL_NO_SURFACE;
459 }
460
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000461 mSurfaceSet.insert(surface);
462
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000463 return success(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000464}
465
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000466EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000467{
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000468 EGLint width = 0, height = 0;
469 EGLenum textureFormat = EGL_NO_TEXTURE;
470 EGLenum textureTarget = EGL_NO_TEXTURE;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000471 const Config *configuration = mConfigSet.get(config);
472
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000473 if (attribList)
474 {
475 while (*attribList != EGL_NONE)
476 {
477 switch (attribList[0])
478 {
479 case EGL_WIDTH:
480 width = attribList[1];
481 break;
482 case EGL_HEIGHT:
483 height = attribList[1];
484 break;
485 case EGL_LARGEST_PBUFFER:
486 if (attribList[1] != EGL_FALSE)
487 UNIMPLEMENTED(); // FIXME
488 break;
489 case EGL_TEXTURE_FORMAT:
490 switch (attribList[1])
491 {
492 case EGL_NO_TEXTURE:
493 case EGL_TEXTURE_RGB:
494 case EGL_TEXTURE_RGBA:
495 textureFormat = attribList[1];
496 break;
497 default:
498 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
499 }
500 break;
501 case EGL_TEXTURE_TARGET:
502 switch (attribList[1])
503 {
504 case EGL_NO_TEXTURE:
505 case EGL_TEXTURE_2D:
506 textureTarget = attribList[1];
507 break;
508 default:
509 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
510 }
511 break;
512 case EGL_MIPMAP_TEXTURE:
513 if (attribList[1] != EGL_FALSE)
514 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
515 break;
516 case EGL_VG_COLORSPACE:
517 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
518 case EGL_VG_ALPHA_FORMAT:
519 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
520 default:
521 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
522 }
523
524 attribList += 2;
525 }
526 }
527
528 if (width < 0 || height < 0)
529 {
530 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
531 }
532
533 if (width == 0 || height == 0)
534 {
535 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
536 }
537
538 if (textureFormat != EGL_NO_TEXTURE && !getNonPow2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
539 {
540 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
541 }
542
543 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
544 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
545 {
546 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
547 }
548
549 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
550 {
551 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
552 }
553
554 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
555 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
556 {
557 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
558 }
559
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000560 Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
561
562 if (!surface->initialize())
563 {
564 delete surface;
565 return EGL_NO_SURFACE;
566 }
567
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000568 mSurfaceSet.insert(surface);
569
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000570 return success(surface);
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000571}
572
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000573EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext)
574{
575 if (!mDevice)
576 {
577 if (!createDevice())
578 {
579 return NULL;
580 }
581 }
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000582 else if (isDeviceLost()) // Lost device
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000583 {
daniel@transgaming.com6c4dba02011-05-26 14:15:31 +0000584 // Release surface resources to make the Reset() succeed
585 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
586 {
587 (*surface)->release();
588 }
589
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000590 if (!resetDevice())
591 {
592 return NULL;
593 }
594
595 // Restore any surfaces that may have been lost
596 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
597 {
598 (*surface)->resetSwapChain();
599 }
600 }
601
602 const egl::Config *config = mConfigSet.get(configHandle);
603
604 gl::Context *context = glCreateContext(config, shareContext);
605 mContextSet.insert(context);
606
607 return context;
608}
609
610void Display::destroySurface(egl::Surface *surface)
611{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000612 delete surface;
613 mSurfaceSet.erase(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000614}
615
616void Display::destroyContext(gl::Context *context)
617{
618 glDestroyContext(context);
619 mContextSet.erase(context);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000620}
621
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000622bool Display::isInitialized() const
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000623{
624 return mD3d9 != NULL && mConfigSet.size() > 0;
625}
626
627bool Display::isValidConfig(EGLConfig config)
628{
629 return mConfigSet.get(config) != NULL;
630}
631
632bool Display::isValidContext(gl::Context *context)
633{
634 return mContextSet.find(context) != mContextSet.end();
635}
636
637bool Display::isValidSurface(egl::Surface *surface)
638{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000639 return mSurfaceSet.find(surface) != mSurfaceSet.end();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000640}
641
642bool Display::hasExistingWindowSurface(HWND window)
643{
644 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
645 {
646 if ((*surface)->getWindowHandle() == window)
647 {
648 return true;
649 }
650 }
651
652 return false;
653}
654
655EGLint Display::getMinSwapInterval()
656{
657 return mMinSwapInterval;
658}
659
660EGLint Display::getMaxSwapInterval()
661{
662 return mMaxSwapInterval;
663}
664
665IDirect3DDevice9 *Display::getDevice()
666{
667 if (!mDevice)
668 {
669 if (!createDevice())
670 {
671 return NULL;
672 }
673 }
674
675 return mDevice;
676}
677
678D3DCAPS9 Display::getDeviceCaps()
679{
680 return mDeviceCaps;
681}
682
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000683bool Display::isDeviceLost()
684{
685 if (mDeviceEx)
686 {
687 return FAILED(mDeviceEx->CheckDeviceState(NULL));
688 }
689 else
690 {
691 return FAILED(mDevice->TestCooperativeLevel());
692 }
693}
694
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000695void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
696{
697 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
698 {
699 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
700 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
701
702 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
703 }
704}
705
706bool Display::getCompressedTextureSupport()
707{
708 D3DDISPLAYMODE currentDisplayMode;
709 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
710
711 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
712}
713
714bool Display::getFloatTextureSupport(bool *filtering, bool *renderable)
715{
716 D3DDISPLAYMODE currentDisplayMode;
717 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
718
719 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
720 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
721 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
722 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
723
724 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
725 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
726 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
727 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
728
729 if (!filtering && !renderable)
730 {
731 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
732 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
733 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
734 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
735 }
736 else
737 {
738 return true;
739 }
740}
741
742bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable)
743{
744 D3DDISPLAYMODE currentDisplayMode;
745 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
746
747 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
748 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
749 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
750 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
751
752 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
753 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
754 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
755 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
756
757 if (!filtering && !renderable)
758 {
759 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
760 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
761 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
762 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
763 }
764 else
765 {
766 return true;
767 }
768}
769
daniel@transgaming.comed828e52010-10-15 17:57:30 +0000770bool Display::getLuminanceTextureSupport()
771{
772 D3DDISPLAYMODE currentDisplayMode;
773 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
774
775 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
776}
777
778bool Display::getLuminanceAlphaTextureSupport()
779{
780 D3DDISPLAYMODE currentDisplayMode;
781 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
782
783 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
784}
785
jbauman@chromium.orgae345802011-03-30 22:04:25 +0000786bool Display::getNonPow2TextureSupport()
787{
788 return !(mDeviceCaps.TextureCaps & (D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL));
789}
790
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000791D3DPOOL Display::getBufferPool(DWORD usage) const
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000792{
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000793 if (mD3d9Ex != NULL)
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000794 {
795 return D3DPOOL_DEFAULT;
796 }
797 else
798 {
799 if (!(usage & D3DUSAGE_DYNAMIC))
800 {
801 return D3DPOOL_MANAGED;
802 }
803 }
804
805 return D3DPOOL_DEFAULT;
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000806}
807
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000808bool Display::getEventQuerySupport()
809{
810 IDirect3DQuery9 *query;
811 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
812 if (SUCCEEDED(result))
813 {
814 query->Release();
815 }
816
817 return result != D3DERR_NOTAVAILABLE;
818}
819
820D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
821{
822 D3DPRESENT_PARAMETERS presentParameters = {0};
823
824 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
825 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
826 presentParameters.BackBufferCount = 1;
827 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
828 presentParameters.BackBufferWidth = 1;
829 presentParameters.BackBufferHeight = 1;
830 presentParameters.EnableAutoDepthStencil = FALSE;
831 presentParameters.Flags = 0;
832 presentParameters.hDeviceWindow = mDeviceWindow;
833 presentParameters.MultiSampleQuality = 0;
834 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
835 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
836 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
837 presentParameters.Windowed = TRUE;
838
839 return presentParameters;
840}
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000841
842void Display::initExtensionString()
843{
844 mExtensionString += "EGL_ANGLE_query_surface_pointer ";
845
846 if (isD3d9ExDevice()) {
847 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
daniel@transgaming.com2b720c92011-05-13 16:05:22 +0000848 mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000849 }
850
851 std::string::size_type end = mExtensionString.find_last_not_of(' ');
852 if (end != std::string::npos)
853 {
854 mExtensionString.resize(end+1);
855 }
856}
857
858const char *Display::getExtensionString() const
859{
860 return mExtensionString.c_str();
861}
862
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000863// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
864// We test this using D3D9 by checking support for the R16F format.
865bool Display::getVertexTextureSupport() const
866{
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000867 if (!isInitialized() || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
868 {
869 return false;
870 }
871
872 D3DDISPLAYMODE currentDisplayMode;
873 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
874
875 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
876
877 return SUCCEEDED(result);
878}
879
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000880}