blob: b8b5e2f29503d29bafaa6d868fd404ffb2b22a7d [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
144 const D3DFORMAT renderTargetFormats[] =
145 {
146 D3DFMT_A1R5G5B5,
147 // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
148 D3DFMT_A8R8G8B8,
149 D3DFMT_R5G6B5,
daniel@transgaming.com73a5db62010-10-15 17:58:13 +0000150 // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000151 D3DFMT_X8R8G8B8
152 };
153
154 const D3DFORMAT depthStencilFormats[] =
155 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000156 D3DFMT_UNKNOWN,
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000157 // D3DFMT_D16_LOCKABLE,
158 D3DFMT_D32,
159 // D3DFMT_D15S1,
160 D3DFMT_D24S8,
161 D3DFMT_D24X8,
162 // D3DFMT_D24X4S4,
163 D3DFMT_D16,
164 // D3DFMT_D32F_LOCKABLE,
165 // D3DFMT_D24FS8
166 };
167
168 D3DDISPLAYMODE currentDisplayMode;
169 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
170
171 ConfigSet configSet;
172
173 for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++)
174 {
175 D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex];
176
177 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
178
179 if (SUCCEEDED(result))
180 {
181 for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++)
182 {
183 D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex];
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000184 HRESULT result = D3D_OK;
185
186 if(depthStencilFormat != D3DFMT_UNKNOWN)
187 {
188 result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
189 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000190
191 if (SUCCEEDED(result))
192 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000193 if(depthStencilFormat != D3DFMT_UNKNOWN)
194 {
195 result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
196 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000197
198 if (SUCCEEDED(result))
199 {
200 // FIXME: enumerate multi-sampling
201
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000202 configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0,
203 mDeviceCaps.MaxTextureWidth, mDeviceCaps.MaxTextureHeight);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000204 }
205 }
206 }
207 }
208 }
209
210 // Give the sorted configs a unique ID and store them internally
211 EGLint index = 1;
212 for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
213 {
214 Config configuration = *config;
215 configuration.mConfigID = index;
216 index++;
217
218 mConfigSet.mSet.insert(configuration);
219 }
220 }
221
222 if (!isInitialized())
223 {
224 terminate();
225
226 return false;
227 }
228
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000229 initExtensionString();
230
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000231 static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
232 static const TCHAR className[] = TEXT("STATIC");
233
234 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
235
236 return true;
237}
238
239void Display::terminate()
240{
241 while (!mSurfaceSet.empty())
242 {
243 destroySurface(*mSurfaceSet.begin());
244 }
245
246 while (!mContextSet.empty())
247 {
248 destroyContext(*mContextSet.begin());
249 }
250
251 if (mDevice)
252 {
253 // 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 +0000254 if (isDeviceLost())
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000255 {
256 resetDevice();
257 }
258
259 mDevice->Release();
260 mDevice = NULL;
261 }
262
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000263 if (mDeviceEx)
264 {
265 mDeviceEx->Release();
266 mDeviceEx = NULL;
267 }
268
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000269 if (mD3d9)
270 {
271 mD3d9->Release();
272 mD3d9 = NULL;
273 }
274
275 if (mDeviceWindow)
276 {
277 DestroyWindow(mDeviceWindow);
278 mDeviceWindow = NULL;
279 }
280
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000281 if (mD3d9Ex)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000282 {
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000283 mD3d9Ex->Release();
284 mD3d9Ex = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000285 }
286
287 if (mD3d9Module)
288 {
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000289 mD3d9Module = NULL;
290 }
291}
292
293void Display::startScene()
294{
295 if (!mSceneStarted)
296 {
297 long result = mDevice->BeginScene();
298 ASSERT(SUCCEEDED(result));
299 mSceneStarted = true;
300 }
301}
302
303void Display::endScene()
304{
305 if (mSceneStarted)
306 {
307 long result = mDevice->EndScene();
308 ASSERT(SUCCEEDED(result));
309 mSceneStarted = false;
310 }
311}
312
313bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
314{
315 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
316}
317
318bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
319{
320 const egl::Config *configuration = mConfigSet.get(config);
321
322 switch (attribute)
323 {
324 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
325 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
326 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
327 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
328 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
329 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
330 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
331 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
332 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
333 case EGL_LEVEL: *value = configuration->mLevel; break;
334 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
335 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
336 case EGL_SAMPLES: *value = configuration->mSamples; break;
337 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
338 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
339 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
340 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
341 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
342 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
343 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
344 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
345 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
346 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
347 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
348 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
349 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
350 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
351 case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
352 case EGL_CONFORMANT: *value = configuration->mConformant; break;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000353 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
354 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
355 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000356 default:
357 return false;
358 }
359
360 return true;
361}
362
363bool Display::createDevice()
364{
365 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
366 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
367
368 HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
369
370 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
371 {
372 return error(EGL_BAD_ALLOC, false);
373 }
374
375 if (FAILED(result))
376 {
377 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
378
379 if (FAILED(result))
380 {
381 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
382 return error(EGL_BAD_ALLOC, false);
383 }
384 }
385
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000386 if (mD3d9Ex)
387 {
388 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
389 ASSERT(SUCCEEDED(result));
390 }
391
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000392 // Permanent non-default states
393 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
394
395 mSceneStarted = false;
396
397 return true;
398}
399
400bool Display::resetDevice()
401{
402 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
403 HRESULT result;
404
405 do
406 {
407 Sleep(0); // Give the graphics driver some CPU time
408
409 result = mDevice->Reset(&presentParameters);
410 }
411 while (result == D3DERR_DEVICELOST);
412
413 if (FAILED(result))
414 {
415 return error(EGL_BAD_ALLOC, false);
416 }
417
418 ASSERT(SUCCEEDED(result));
419
420 return true;
421}
422
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000423EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000424{
425 const Config *configuration = mConfigSet.get(config);
426
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000427 if (attribList)
428 {
429 while (*attribList != EGL_NONE)
430 {
431 switch (attribList[0])
432 {
433 case EGL_RENDER_BUFFER:
434 switch (attribList[1])
435 {
436 case EGL_BACK_BUFFER:
437 break;
438 case EGL_SINGLE_BUFFER:
439 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
440 default:
441 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
442 }
443 break;
444 case EGL_VG_COLORSPACE:
445 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
446 case EGL_VG_ALPHA_FORMAT:
447 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
448 default:
449 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
450 }
451
452 attribList += 2;
453 }
454 }
455
456 if (hasExistingWindowSurface(window))
457 {
458 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
459 }
460
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000461 Surface *surface = new Surface(this, configuration, window);
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000462
463 if (!surface->initialize())
464 {
465 delete surface;
466 return EGL_NO_SURFACE;
467 }
468
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000469 mSurfaceSet.insert(surface);
470
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000471 return success(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000472}
473
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000474EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000475{
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000476 EGLint width = 0, height = 0;
477 EGLenum textureFormat = EGL_NO_TEXTURE;
478 EGLenum textureTarget = EGL_NO_TEXTURE;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000479 const Config *configuration = mConfigSet.get(config);
480
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000481 if (attribList)
482 {
483 while (*attribList != EGL_NONE)
484 {
485 switch (attribList[0])
486 {
487 case EGL_WIDTH:
488 width = attribList[1];
489 break;
490 case EGL_HEIGHT:
491 height = attribList[1];
492 break;
493 case EGL_LARGEST_PBUFFER:
494 if (attribList[1] != EGL_FALSE)
495 UNIMPLEMENTED(); // FIXME
496 break;
497 case EGL_TEXTURE_FORMAT:
498 switch (attribList[1])
499 {
500 case EGL_NO_TEXTURE:
501 case EGL_TEXTURE_RGB:
502 case EGL_TEXTURE_RGBA:
503 textureFormat = attribList[1];
504 break;
505 default:
506 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
507 }
508 break;
509 case EGL_TEXTURE_TARGET:
510 switch (attribList[1])
511 {
512 case EGL_NO_TEXTURE:
513 case EGL_TEXTURE_2D:
514 textureTarget = attribList[1];
515 break;
516 default:
517 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
518 }
519 break;
520 case EGL_MIPMAP_TEXTURE:
521 if (attribList[1] != EGL_FALSE)
522 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
523 break;
524 case EGL_VG_COLORSPACE:
525 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
526 case EGL_VG_ALPHA_FORMAT:
527 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
528 default:
529 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
530 }
531
532 attribList += 2;
533 }
534 }
535
536 if (width < 0 || height < 0)
537 {
538 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
539 }
540
541 if (width == 0 || height == 0)
542 {
543 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
544 }
545
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +0000546 if (textureFormat != EGL_NO_TEXTURE && !getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000547 {
548 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
549 }
550
551 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
552 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
553 {
554 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
555 }
556
557 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
558 {
559 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
560 }
561
562 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
563 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
564 {
565 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
566 }
567
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000568 Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
569
570 if (!surface->initialize())
571 {
572 delete surface;
573 return EGL_NO_SURFACE;
574 }
575
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000576 mSurfaceSet.insert(surface);
577
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000578 return success(surface);
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000579}
580
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000581EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext)
582{
583 if (!mDevice)
584 {
585 if (!createDevice())
586 {
587 return NULL;
588 }
589 }
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000590 else if (isDeviceLost()) // Lost device
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000591 {
daniel@transgaming.com6c4dba02011-05-26 14:15:31 +0000592 // Release surface resources to make the Reset() succeed
593 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
594 {
595 (*surface)->release();
596 }
597
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000598 if (!resetDevice())
599 {
600 return NULL;
601 }
602
603 // Restore any surfaces that may have been lost
604 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
605 {
606 (*surface)->resetSwapChain();
607 }
608 }
609
610 const egl::Config *config = mConfigSet.get(configHandle);
611
612 gl::Context *context = glCreateContext(config, shareContext);
613 mContextSet.insert(context);
614
615 return context;
616}
617
618void Display::destroySurface(egl::Surface *surface)
619{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000620 delete surface;
621 mSurfaceSet.erase(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000622}
623
624void Display::destroyContext(gl::Context *context)
625{
626 glDestroyContext(context);
627 mContextSet.erase(context);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000628}
629
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000630bool Display::isInitialized() const
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000631{
632 return mD3d9 != NULL && mConfigSet.size() > 0;
633}
634
635bool Display::isValidConfig(EGLConfig config)
636{
637 return mConfigSet.get(config) != NULL;
638}
639
640bool Display::isValidContext(gl::Context *context)
641{
642 return mContextSet.find(context) != mContextSet.end();
643}
644
645bool Display::isValidSurface(egl::Surface *surface)
646{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000647 return mSurfaceSet.find(surface) != mSurfaceSet.end();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000648}
649
650bool Display::hasExistingWindowSurface(HWND window)
651{
652 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
653 {
654 if ((*surface)->getWindowHandle() == window)
655 {
656 return true;
657 }
658 }
659
660 return false;
661}
662
663EGLint Display::getMinSwapInterval()
664{
665 return mMinSwapInterval;
666}
667
668EGLint Display::getMaxSwapInterval()
669{
670 return mMaxSwapInterval;
671}
672
673IDirect3DDevice9 *Display::getDevice()
674{
675 if (!mDevice)
676 {
677 if (!createDevice())
678 {
679 return NULL;
680 }
681 }
682
683 return mDevice;
684}
685
686D3DCAPS9 Display::getDeviceCaps()
687{
688 return mDeviceCaps;
689}
690
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000691bool Display::isDeviceLost()
692{
693 if (mDeviceEx)
694 {
695 return FAILED(mDeviceEx->CheckDeviceState(NULL));
696 }
697 else
698 {
699 return FAILED(mDevice->TestCooperativeLevel());
700 }
701}
702
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000703void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
704{
705 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
706 {
707 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
708 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
709
710 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
711 }
712}
713
714bool Display::getCompressedTextureSupport()
715{
716 D3DDISPLAYMODE currentDisplayMode;
717 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
718
719 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
720}
721
722bool Display::getFloatTextureSupport(bool *filtering, bool *renderable)
723{
724 D3DDISPLAYMODE currentDisplayMode;
725 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
726
727 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
728 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
729 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
730 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
731
732 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
733 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
734 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
735 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
736
737 if (!filtering && !renderable)
738 {
739 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
740 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
741 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
742 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
743 }
744 else
745 {
746 return true;
747 }
748}
749
750bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable)
751{
752 D3DDISPLAYMODE currentDisplayMode;
753 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
754
755 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
756 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
757 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
758 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
759
760 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
761 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
762 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
763 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
764
765 if (!filtering && !renderable)
766 {
767 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
768 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
769 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
770 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
771 }
772 else
773 {
774 return true;
775 }
776}
777
daniel@transgaming.comed828e52010-10-15 17:57:30 +0000778bool Display::getLuminanceTextureSupport()
779{
780 D3DDISPLAYMODE currentDisplayMode;
781 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
782
783 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
784}
785
786bool Display::getLuminanceAlphaTextureSupport()
787{
788 D3DDISPLAYMODE currentDisplayMode;
789 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
790
791 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
792}
793
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000794D3DPOOL Display::getBufferPool(DWORD usage) const
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000795{
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000796 if (mD3d9Ex != NULL)
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000797 {
798 return D3DPOOL_DEFAULT;
799 }
800 else
801 {
802 if (!(usage & D3DUSAGE_DYNAMIC))
803 {
804 return D3DPOOL_MANAGED;
805 }
806 }
807
808 return D3DPOOL_DEFAULT;
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000809}
810
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000811bool Display::getEventQuerySupport()
812{
813 IDirect3DQuery9 *query;
814 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
815 if (SUCCEEDED(result))
816 {
817 query->Release();
818 }
819
820 return result != D3DERR_NOTAVAILABLE;
821}
822
823D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
824{
825 D3DPRESENT_PARAMETERS presentParameters = {0};
826
827 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
828 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
829 presentParameters.BackBufferCount = 1;
830 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
831 presentParameters.BackBufferWidth = 1;
832 presentParameters.BackBufferHeight = 1;
833 presentParameters.EnableAutoDepthStencil = FALSE;
834 presentParameters.Flags = 0;
835 presentParameters.hDeviceWindow = mDeviceWindow;
836 presentParameters.MultiSampleQuality = 0;
837 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
838 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
839 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
840 presentParameters.Windowed = TRUE;
841
842 return presentParameters;
843}
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000844
845void Display::initExtensionString()
846{
847 mExtensionString += "EGL_ANGLE_query_surface_pointer ";
848
849 if (isD3d9ExDevice()) {
850 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
daniel@transgaming.com2b720c92011-05-13 16:05:22 +0000851 mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000852 }
853
854 std::string::size_type end = mExtensionString.find_last_not_of(' ');
855 if (end != std::string::npos)
856 {
857 mExtensionString.resize(end+1);
858 }
859}
860
861const char *Display::getExtensionString() const
862{
863 return mExtensionString.c_str();
864}
865
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000866// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
867// We test this using D3D9 by checking support for the R16F format.
868bool Display::getVertexTextureSupport() const
869{
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000870 if (!isInitialized() || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
871 {
872 return false;
873 }
874
875 D3DDISPLAYMODE currentDisplayMode;
876 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
877
878 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
879
880 return SUCCEEDED(result);
881}
882
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +0000883bool Display::getNonPower2TextureSupport() const
884{
885 return !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
886 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
887 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
888}
889
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000890}