blob: 1d64f9a10d0a0791a1d52cddacf15a9ceb582893 [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
baustin@google.com250f06c2011-06-06 16:59:53 +000021// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
22#define REF_RAST 0
23
24// The "Debug This Pixel..." feature in PIX often fails when using the
25// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7
26// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file.
27#if !defined(ANGLE_ENABLE_D3D9EX)
28// Enables use of the IDirect3D9Ex interface, when available
29#define ANGLE_ENABLE_D3D9EX 1
30#endif // !defined(ANGLE_ENABLE_D3D9EX)
daniel@transgaming.come979ead2010-09-23 18:03:14 +000031
32namespace egl
33{
34Display::Display(HDC deviceContext) : mDc(deviceContext)
35{
36 mD3d9Module = NULL;
37
38 mD3d9 = NULL;
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000039 mD3d9Ex = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +000040 mDevice = NULL;
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000041 mDeviceEx = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +000042 mDeviceWindow = NULL;
43
44 mAdapter = D3DADAPTER_DEFAULT;
45
46 #if REF_RAST == 1 || defined(FORCE_REF_RAST)
47 mDeviceType = D3DDEVTYPE_REF;
48 #else
49 mDeviceType = D3DDEVTYPE_HAL;
50 #endif
51
52 mMinSwapInterval = 1;
53 mMaxSwapInterval = 1;
54}
55
56Display::~Display()
57{
58 terminate();
59}
60
61bool Display::initialize()
62{
63 if (isInitialized())
64 {
65 return true;
66 }
67
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +000068 mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
daniel@transgaming.come979ead2010-09-23 18:03:14 +000069 if (mD3d9Module == NULL)
70 {
71 terminate();
72 return false;
73 }
74
daniel@transgaming.come979ead2010-09-23 18:03:14 +000075 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
76 Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
77
78 // Use Direct3D9Ex if available. Among other things, this version is less
79 // inclined to report a lost context, for example when the user switches
80 // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
baustin@google.com250f06c2011-06-06 16:59:53 +000081 if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
daniel@transgaming.come979ead2010-09-23 18:03:14 +000082 {
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000083 ASSERT(mD3d9Ex);
84 mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
daniel@transgaming.come979ead2010-09-23 18:03:14 +000085 ASSERT(mD3d9);
86 }
87 else
88 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +000089 mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
daniel@transgaming.come979ead2010-09-23 18:03:14 +000090 }
91
92 if (mD3d9)
93 {
94 if (mDc != NULL)
95 {
96 // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
97 }
98
99 HRESULT result;
100
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000101 // Give up on getting device caps after about one second.
102 for (int i = 0; i < 10; ++i)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000103 {
104 result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000105
106 if (SUCCEEDED(result))
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000107 {
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000108 break;
109 }
110 else if (result == D3DERR_NOTAVAILABLE)
111 {
112 Sleep(100); // Give the driver some time to initialize/recover
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000113 }
114 else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
115 {
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000116 terminate();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000117 return error(EGL_BAD_ALLOC, false);
118 }
119 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000120
121 if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
122 {
123 terminate();
124 return error(EGL_NOT_INITIALIZED, false);
125 }
126
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000127 // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
128 // This is required by Texture2D::convertToRenderTarget.
129 if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
130 {
131 terminate();
132 return error(EGL_NOT_INITIALIZED, false);
133 }
134
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000135 mMinSwapInterval = 4;
136 mMaxSwapInterval = 0;
137
138 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {mMinSwapInterval = std::min(mMinSwapInterval, 0); mMaxSwapInterval = std::max(mMaxSwapInterval, 0);}
139 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) {mMinSwapInterval = std::min(mMinSwapInterval, 1); mMaxSwapInterval = std::max(mMaxSwapInterval, 1);}
140 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) {mMinSwapInterval = std::min(mMinSwapInterval, 2); mMaxSwapInterval = std::max(mMaxSwapInterval, 2);}
141 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);}
142 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);}
143
jbauman@chromium.org03208d52011-06-15 01:15:24 +0000144 mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
145
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000146 const D3DFORMAT renderTargetFormats[] =
147 {
148 D3DFMT_A1R5G5B5,
149 // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
150 D3DFMT_A8R8G8B8,
151 D3DFMT_R5G6B5,
daniel@transgaming.com73a5db62010-10-15 17:58:13 +0000152 // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000153 D3DFMT_X8R8G8B8
154 };
155
156 const D3DFORMAT depthStencilFormats[] =
157 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000158 D3DFMT_UNKNOWN,
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000159 // D3DFMT_D16_LOCKABLE,
160 D3DFMT_D32,
161 // D3DFMT_D15S1,
162 D3DFMT_D24S8,
163 D3DFMT_D24X8,
164 // D3DFMT_D24X4S4,
165 D3DFMT_D16,
166 // D3DFMT_D32F_LOCKABLE,
167 // D3DFMT_D24FS8
168 };
169
170 D3DDISPLAYMODE currentDisplayMode;
171 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
172
173 ConfigSet configSet;
174
175 for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++)
176 {
177 D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex];
178
179 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
180
181 if (SUCCEEDED(result))
182 {
183 for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++)
184 {
185 D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex];
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000186 HRESULT result = D3D_OK;
187
188 if(depthStencilFormat != D3DFMT_UNKNOWN)
189 {
190 result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
191 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000192
193 if (SUCCEEDED(result))
194 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000195 if(depthStencilFormat != D3DFMT_UNKNOWN)
196 {
197 result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
198 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000199
200 if (SUCCEEDED(result))
201 {
202 // FIXME: enumerate multi-sampling
203
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000204 configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0,
205 mDeviceCaps.MaxTextureWidth, mDeviceCaps.MaxTextureHeight);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000206 }
207 }
208 }
209 }
210 }
211
212 // Give the sorted configs a unique ID and store them internally
213 EGLint index = 1;
214 for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
215 {
216 Config configuration = *config;
217 configuration.mConfigID = index;
218 index++;
219
220 mConfigSet.mSet.insert(configuration);
221 }
222 }
223
224 if (!isInitialized())
225 {
226 terminate();
227
228 return false;
229 }
230
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000231 initExtensionString();
232
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000233 static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
234 static const TCHAR className[] = TEXT("STATIC");
235
236 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
237
238 return true;
239}
240
241void Display::terminate()
242{
243 while (!mSurfaceSet.empty())
244 {
245 destroySurface(*mSurfaceSet.begin());
246 }
247
248 while (!mContextSet.empty())
249 {
250 destroyContext(*mContextSet.begin());
251 }
252
253 if (mDevice)
254 {
255 // 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 +0000256 if (isDeviceLost())
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000257 {
258 resetDevice();
259 }
260
261 mDevice->Release();
262 mDevice = NULL;
263 }
264
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000265 if (mDeviceEx)
266 {
267 mDeviceEx->Release();
268 mDeviceEx = NULL;
269 }
270
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000271 if (mD3d9)
272 {
273 mD3d9->Release();
274 mD3d9 = NULL;
275 }
276
277 if (mDeviceWindow)
278 {
279 DestroyWindow(mDeviceWindow);
280 mDeviceWindow = NULL;
281 }
282
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000283 if (mD3d9Ex)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000284 {
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000285 mD3d9Ex->Release();
286 mD3d9Ex = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000287 }
288
289 if (mD3d9Module)
290 {
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000291 mD3d9Module = NULL;
292 }
293}
294
295void Display::startScene()
296{
297 if (!mSceneStarted)
298 {
299 long result = mDevice->BeginScene();
300 ASSERT(SUCCEEDED(result));
301 mSceneStarted = true;
302 }
303}
304
305void Display::endScene()
306{
307 if (mSceneStarted)
308 {
309 long result = mDevice->EndScene();
310 ASSERT(SUCCEEDED(result));
311 mSceneStarted = false;
312 }
313}
314
315bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
316{
317 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
318}
319
320bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
321{
322 const egl::Config *configuration = mConfigSet.get(config);
323
324 switch (attribute)
325 {
326 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
327 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
328 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
329 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
330 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
331 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
332 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
333 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
334 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
335 case EGL_LEVEL: *value = configuration->mLevel; break;
336 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
337 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
338 case EGL_SAMPLES: *value = configuration->mSamples; break;
339 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
340 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
341 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
342 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
343 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
344 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
345 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
346 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
347 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
348 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
349 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
350 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
351 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
352 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
353 case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
354 case EGL_CONFORMANT: *value = configuration->mConformant; break;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000355 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
356 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
357 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000358 default:
359 return false;
360 }
361
362 return true;
363}
364
365bool Display::createDevice()
366{
367 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
368 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
369
370 HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
371
372 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
373 {
374 return error(EGL_BAD_ALLOC, false);
375 }
376
377 if (FAILED(result))
378 {
379 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
380
381 if (FAILED(result))
382 {
383 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
384 return error(EGL_BAD_ALLOC, false);
385 }
386 }
387
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000388 if (mD3d9Ex)
389 {
390 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
391 ASSERT(SUCCEEDED(result));
392 }
393
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000394 // Permanent non-default states
395 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
396
397 mSceneStarted = false;
398
399 return true;
400}
401
402bool Display::resetDevice()
403{
404 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
405 HRESULT result;
406
407 do
408 {
409 Sleep(0); // Give the graphics driver some CPU time
410
411 result = mDevice->Reset(&presentParameters);
412 }
413 while (result == D3DERR_DEVICELOST);
414
415 if (FAILED(result))
416 {
417 return error(EGL_BAD_ALLOC, false);
418 }
419
420 ASSERT(SUCCEEDED(result));
421
422 return true;
423}
424
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000425EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000426{
427 const Config *configuration = mConfigSet.get(config);
428
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000429 if (attribList)
430 {
431 while (*attribList != EGL_NONE)
432 {
433 switch (attribList[0])
434 {
435 case EGL_RENDER_BUFFER:
436 switch (attribList[1])
437 {
438 case EGL_BACK_BUFFER:
439 break;
440 case EGL_SINGLE_BUFFER:
441 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
442 default:
443 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
444 }
445 break;
446 case EGL_VG_COLORSPACE:
447 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
448 case EGL_VG_ALPHA_FORMAT:
449 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
450 default:
451 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
452 }
453
454 attribList += 2;
455 }
456 }
457
458 if (hasExistingWindowSurface(window))
459 {
460 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
461 }
462
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000463 Surface *surface = new Surface(this, configuration, window);
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000464
465 if (!surface->initialize())
466 {
467 delete surface;
468 return EGL_NO_SURFACE;
469 }
470
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000471 mSurfaceSet.insert(surface);
472
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000473 return success(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000474}
475
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000476EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000477{
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000478 EGLint width = 0, height = 0;
479 EGLenum textureFormat = EGL_NO_TEXTURE;
480 EGLenum textureTarget = EGL_NO_TEXTURE;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000481 const Config *configuration = mConfigSet.get(config);
482
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000483 if (attribList)
484 {
485 while (*attribList != EGL_NONE)
486 {
487 switch (attribList[0])
488 {
489 case EGL_WIDTH:
490 width = attribList[1];
491 break;
492 case EGL_HEIGHT:
493 height = attribList[1];
494 break;
495 case EGL_LARGEST_PBUFFER:
496 if (attribList[1] != EGL_FALSE)
497 UNIMPLEMENTED(); // FIXME
498 break;
499 case EGL_TEXTURE_FORMAT:
500 switch (attribList[1])
501 {
502 case EGL_NO_TEXTURE:
503 case EGL_TEXTURE_RGB:
504 case EGL_TEXTURE_RGBA:
505 textureFormat = attribList[1];
506 break;
507 default:
508 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
509 }
510 break;
511 case EGL_TEXTURE_TARGET:
512 switch (attribList[1])
513 {
514 case EGL_NO_TEXTURE:
515 case EGL_TEXTURE_2D:
516 textureTarget = attribList[1];
517 break;
518 default:
519 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
520 }
521 break;
522 case EGL_MIPMAP_TEXTURE:
523 if (attribList[1] != EGL_FALSE)
524 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
525 break;
526 case EGL_VG_COLORSPACE:
527 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
528 case EGL_VG_ALPHA_FORMAT:
529 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
530 default:
531 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
532 }
533
534 attribList += 2;
535 }
536 }
537
538 if (width < 0 || height < 0)
539 {
540 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
541 }
542
543 if (width == 0 || height == 0)
544 {
545 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
546 }
547
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +0000548 if (textureFormat != EGL_NO_TEXTURE && !getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000549 {
550 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
551 }
552
553 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
554 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
555 {
556 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
557 }
558
559 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
560 {
561 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
562 }
563
564 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
565 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
566 {
567 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
568 }
569
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000570 Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
571
572 if (!surface->initialize())
573 {
574 delete surface;
575 return EGL_NO_SURFACE;
576 }
577
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000578 mSurfaceSet.insert(surface);
579
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000580 return success(surface);
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000581}
582
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000583EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext)
584{
585 if (!mDevice)
586 {
587 if (!createDevice())
588 {
589 return NULL;
590 }
591 }
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000592 else if (isDeviceLost()) // Lost device
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000593 {
daniel@transgaming.com6c4dba02011-05-26 14:15:31 +0000594 // Release surface resources to make the Reset() succeed
595 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
596 {
597 (*surface)->release();
598 }
599
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000600 if (!resetDevice())
601 {
602 return NULL;
603 }
604
605 // Restore any surfaces that may have been lost
606 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
607 {
608 (*surface)->resetSwapChain();
609 }
610 }
611
612 const egl::Config *config = mConfigSet.get(configHandle);
613
614 gl::Context *context = glCreateContext(config, shareContext);
615 mContextSet.insert(context);
616
617 return context;
618}
619
620void Display::destroySurface(egl::Surface *surface)
621{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000622 delete surface;
623 mSurfaceSet.erase(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000624}
625
626void Display::destroyContext(gl::Context *context)
627{
628 glDestroyContext(context);
629 mContextSet.erase(context);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000630}
631
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000632bool Display::isInitialized() const
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000633{
634 return mD3d9 != NULL && mConfigSet.size() > 0;
635}
636
637bool Display::isValidConfig(EGLConfig config)
638{
639 return mConfigSet.get(config) != NULL;
640}
641
642bool Display::isValidContext(gl::Context *context)
643{
644 return mContextSet.find(context) != mContextSet.end();
645}
646
647bool Display::isValidSurface(egl::Surface *surface)
648{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000649 return mSurfaceSet.find(surface) != mSurfaceSet.end();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000650}
651
652bool Display::hasExistingWindowSurface(HWND window)
653{
654 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
655 {
656 if ((*surface)->getWindowHandle() == window)
657 {
658 return true;
659 }
660 }
661
662 return false;
663}
664
665EGLint Display::getMinSwapInterval()
666{
667 return mMinSwapInterval;
668}
669
670EGLint Display::getMaxSwapInterval()
671{
672 return mMaxSwapInterval;
673}
674
675IDirect3DDevice9 *Display::getDevice()
676{
677 if (!mDevice)
678 {
679 if (!createDevice())
680 {
681 return NULL;
682 }
683 }
684
685 return mDevice;
686}
687
688D3DCAPS9 Display::getDeviceCaps()
689{
690 return mDeviceCaps;
691}
692
jbauman@chromium.org03208d52011-06-15 01:15:24 +0000693D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier()
694{
695 return &mAdapterIdentifier;
696}
697
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000698bool Display::isDeviceLost()
699{
700 if (mDeviceEx)
701 {
702 return FAILED(mDeviceEx->CheckDeviceState(NULL));
703 }
704 else
705 {
706 return FAILED(mDevice->TestCooperativeLevel());
707 }
708}
709
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000710void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
711{
712 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
713 {
714 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
715 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
716
717 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
718 }
719}
720
721bool Display::getCompressedTextureSupport()
722{
723 D3DDISPLAYMODE currentDisplayMode;
724 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
725
726 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
727}
728
729bool Display::getFloatTextureSupport(bool *filtering, bool *renderable)
730{
731 D3DDISPLAYMODE currentDisplayMode;
732 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
733
734 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
735 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
736 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
737 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
738
739 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
740 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
741 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
742 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
743
744 if (!filtering && !renderable)
745 {
746 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
747 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
748 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
749 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
750 }
751 else
752 {
753 return true;
754 }
755}
756
757bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable)
758{
759 D3DDISPLAYMODE currentDisplayMode;
760 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
761
762 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
763 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
764 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
765 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
766
767 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
768 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
769 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
770 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
771
772 if (!filtering && !renderable)
773 {
774 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
775 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
776 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
777 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
778 }
779 else
780 {
781 return true;
782 }
783}
784
daniel@transgaming.comed828e52010-10-15 17:57:30 +0000785bool Display::getLuminanceTextureSupport()
786{
787 D3DDISPLAYMODE currentDisplayMode;
788 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
789
790 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
791}
792
793bool Display::getLuminanceAlphaTextureSupport()
794{
795 D3DDISPLAYMODE currentDisplayMode;
796 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
797
798 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
799}
800
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000801D3DPOOL Display::getBufferPool(DWORD usage) const
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000802{
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000803 if (mD3d9Ex != NULL)
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000804 {
805 return D3DPOOL_DEFAULT;
806 }
807 else
808 {
809 if (!(usage & D3DUSAGE_DYNAMIC))
810 {
811 return D3DPOOL_MANAGED;
812 }
813 }
814
815 return D3DPOOL_DEFAULT;
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000816}
817
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000818bool Display::getEventQuerySupport()
819{
820 IDirect3DQuery9 *query;
821 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
822 if (SUCCEEDED(result))
823 {
824 query->Release();
825 }
826
827 return result != D3DERR_NOTAVAILABLE;
828}
829
830D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
831{
832 D3DPRESENT_PARAMETERS presentParameters = {0};
833
834 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
835 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
836 presentParameters.BackBufferCount = 1;
837 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
838 presentParameters.BackBufferWidth = 1;
839 presentParameters.BackBufferHeight = 1;
840 presentParameters.EnableAutoDepthStencil = FALSE;
841 presentParameters.Flags = 0;
842 presentParameters.hDeviceWindow = mDeviceWindow;
843 presentParameters.MultiSampleQuality = 0;
844 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
845 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
846 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
847 presentParameters.Windowed = TRUE;
848
849 return presentParameters;
850}
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000851
852void Display::initExtensionString()
853{
854 mExtensionString += "EGL_ANGLE_query_surface_pointer ";
855
856 if (isD3d9ExDevice()) {
857 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
daniel@transgaming.com2b720c92011-05-13 16:05:22 +0000858 mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000859 }
860
861 std::string::size_type end = mExtensionString.find_last_not_of(' ');
862 if (end != std::string::npos)
863 {
864 mExtensionString.resize(end+1);
865 }
866}
867
868const char *Display::getExtensionString() const
869{
870 return mExtensionString.c_str();
871}
872
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000873// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
874// We test this using D3D9 by checking support for the R16F format.
875bool Display::getVertexTextureSupport() const
876{
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000877 if (!isInitialized() || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
878 {
879 return false;
880 }
881
882 D3DDISPLAYMODE currentDisplayMode;
883 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
884
885 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
886
887 return SUCCEEDED(result);
888}
889
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +0000890bool Display::getNonPower2TextureSupport() const
891{
892 return !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
893 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
894 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
895}
896
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000897}