blob: ac51af2f6c66f77a8d964105b9f309de8b72beb8 [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();
kbr@chromium.org1a2cd262011-07-08 17:30:18 +0000300 if (SUCCEEDED(result)) {
301 // This is defensive checking against the device being
302 // lost at unexpected times.
303 mSceneStarted = true;
304 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000305 }
306}
307
308void Display::endScene()
309{
310 if (mSceneStarted)
311 {
kbr@chromium.org1a2cd262011-07-08 17:30:18 +0000312 // EndScene can fail if the device was lost, for example due
313 // to a TDR during a draw call.
314 mDevice->EndScene();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000315 mSceneStarted = false;
316 }
317}
318
319bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
320{
321 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
322}
323
324bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
325{
326 const egl::Config *configuration = mConfigSet.get(config);
327
328 switch (attribute)
329 {
330 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
331 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
332 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
333 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
334 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
335 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
336 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
337 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
338 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
339 case EGL_LEVEL: *value = configuration->mLevel; break;
340 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
341 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
342 case EGL_SAMPLES: *value = configuration->mSamples; break;
343 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
344 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
345 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
346 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
347 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
348 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
349 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
350 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
351 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
352 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
353 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
354 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
355 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
356 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
357 case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
358 case EGL_CONFORMANT: *value = configuration->mConformant; break;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000359 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
360 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
361 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000362 default:
363 return false;
364 }
365
366 return true;
367}
368
369bool Display::createDevice()
370{
371 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
372 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
373
374 HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
375
376 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
377 {
378 return error(EGL_BAD_ALLOC, false);
379 }
380
381 if (FAILED(result))
382 {
383 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
384
385 if (FAILED(result))
386 {
387 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
388 return error(EGL_BAD_ALLOC, false);
389 }
390 }
391
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000392 if (mD3d9Ex)
393 {
394 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
395 ASSERT(SUCCEEDED(result));
396 }
397
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000398 // Permanent non-default states
399 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
400
401 mSceneStarted = false;
402
403 return true;
404}
405
406bool Display::resetDevice()
407{
408 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
409 HRESULT result;
410
411 do
412 {
413 Sleep(0); // Give the graphics driver some CPU time
414
415 result = mDevice->Reset(&presentParameters);
416 }
417 while (result == D3DERR_DEVICELOST);
418
419 if (FAILED(result))
420 {
421 return error(EGL_BAD_ALLOC, false);
422 }
423
424 ASSERT(SUCCEEDED(result));
425
426 return true;
427}
428
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000429EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000430{
431 const Config *configuration = mConfigSet.get(config);
432
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000433 if (attribList)
434 {
435 while (*attribList != EGL_NONE)
436 {
437 switch (attribList[0])
438 {
439 case EGL_RENDER_BUFFER:
440 switch (attribList[1])
441 {
442 case EGL_BACK_BUFFER:
443 break;
444 case EGL_SINGLE_BUFFER:
445 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
446 default:
447 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
448 }
449 break;
450 case EGL_VG_COLORSPACE:
451 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
452 case EGL_VG_ALPHA_FORMAT:
453 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
454 default:
455 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
456 }
457
458 attribList += 2;
459 }
460 }
461
462 if (hasExistingWindowSurface(window))
463 {
464 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
465 }
466
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000467 Surface *surface = new Surface(this, configuration, window);
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000468
469 if (!surface->initialize())
470 {
471 delete surface;
472 return EGL_NO_SURFACE;
473 }
474
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000475 mSurfaceSet.insert(surface);
476
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000477 return success(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000478}
479
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000480EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000481{
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000482 EGLint width = 0, height = 0;
483 EGLenum textureFormat = EGL_NO_TEXTURE;
484 EGLenum textureTarget = EGL_NO_TEXTURE;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000485 const Config *configuration = mConfigSet.get(config);
486
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000487 if (attribList)
488 {
489 while (*attribList != EGL_NONE)
490 {
491 switch (attribList[0])
492 {
493 case EGL_WIDTH:
494 width = attribList[1];
495 break;
496 case EGL_HEIGHT:
497 height = attribList[1];
498 break;
499 case EGL_LARGEST_PBUFFER:
500 if (attribList[1] != EGL_FALSE)
501 UNIMPLEMENTED(); // FIXME
502 break;
503 case EGL_TEXTURE_FORMAT:
504 switch (attribList[1])
505 {
506 case EGL_NO_TEXTURE:
507 case EGL_TEXTURE_RGB:
508 case EGL_TEXTURE_RGBA:
509 textureFormat = attribList[1];
510 break;
511 default:
512 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
513 }
514 break;
515 case EGL_TEXTURE_TARGET:
516 switch (attribList[1])
517 {
518 case EGL_NO_TEXTURE:
519 case EGL_TEXTURE_2D:
520 textureTarget = attribList[1];
521 break;
522 default:
523 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
524 }
525 break;
526 case EGL_MIPMAP_TEXTURE:
527 if (attribList[1] != EGL_FALSE)
528 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
529 break;
530 case EGL_VG_COLORSPACE:
531 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
532 case EGL_VG_ALPHA_FORMAT:
533 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
534 default:
535 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
536 }
537
538 attribList += 2;
539 }
540 }
541
542 if (width < 0 || height < 0)
543 {
544 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
545 }
546
547 if (width == 0 || height == 0)
548 {
549 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
550 }
551
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +0000552 if (textureFormat != EGL_NO_TEXTURE && !getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000553 {
554 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
555 }
556
557 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
558 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
559 {
560 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
561 }
562
563 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
564 {
565 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
566 }
567
568 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
569 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
570 {
571 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
572 }
573
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000574 Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
575
576 if (!surface->initialize())
577 {
578 delete surface;
579 return EGL_NO_SURFACE;
580 }
581
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000582 mSurfaceSet.insert(surface);
583
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000584 return success(surface);
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000585}
586
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000587EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext)
588{
589 if (!mDevice)
590 {
591 if (!createDevice())
592 {
593 return NULL;
594 }
595 }
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000596 else if (isDeviceLost()) // Lost device
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000597 {
daniel@transgaming.com6c4dba02011-05-26 14:15:31 +0000598 // Release surface resources to make the Reset() succeed
599 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
600 {
601 (*surface)->release();
602 }
603
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000604 if (!resetDevice())
605 {
606 return NULL;
607 }
608
609 // Restore any surfaces that may have been lost
610 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
611 {
612 (*surface)->resetSwapChain();
613 }
614 }
615
616 const egl::Config *config = mConfigSet.get(configHandle);
617
618 gl::Context *context = glCreateContext(config, shareContext);
619 mContextSet.insert(context);
620
621 return context;
622}
623
624void Display::destroySurface(egl::Surface *surface)
625{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000626 delete surface;
627 mSurfaceSet.erase(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000628}
629
630void Display::destroyContext(gl::Context *context)
631{
632 glDestroyContext(context);
633 mContextSet.erase(context);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000634}
635
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000636bool Display::isInitialized() const
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000637{
638 return mD3d9 != NULL && mConfigSet.size() > 0;
639}
640
641bool Display::isValidConfig(EGLConfig config)
642{
643 return mConfigSet.get(config) != NULL;
644}
645
646bool Display::isValidContext(gl::Context *context)
647{
648 return mContextSet.find(context) != mContextSet.end();
649}
650
651bool Display::isValidSurface(egl::Surface *surface)
652{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000653 return mSurfaceSet.find(surface) != mSurfaceSet.end();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000654}
655
656bool Display::hasExistingWindowSurface(HWND window)
657{
658 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
659 {
660 if ((*surface)->getWindowHandle() == window)
661 {
662 return true;
663 }
664 }
665
666 return false;
667}
668
669EGLint Display::getMinSwapInterval()
670{
671 return mMinSwapInterval;
672}
673
674EGLint Display::getMaxSwapInterval()
675{
676 return mMaxSwapInterval;
677}
678
679IDirect3DDevice9 *Display::getDevice()
680{
681 if (!mDevice)
682 {
683 if (!createDevice())
684 {
685 return NULL;
686 }
687 }
688
689 return mDevice;
690}
691
692D3DCAPS9 Display::getDeviceCaps()
693{
694 return mDeviceCaps;
695}
696
jbauman@chromium.org03208d52011-06-15 01:15:24 +0000697D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier()
698{
699 return &mAdapterIdentifier;
700}
701
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000702bool Display::isDeviceLost()
703{
704 if (mDeviceEx)
705 {
706 return FAILED(mDeviceEx->CheckDeviceState(NULL));
707 }
708 else
709 {
710 return FAILED(mDevice->TestCooperativeLevel());
711 }
712}
713
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000714void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
715{
716 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
717 {
718 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
719 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
720
721 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
722 }
723}
724
725bool Display::getCompressedTextureSupport()
726{
727 D3DDISPLAYMODE currentDisplayMode;
728 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
729
730 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
731}
732
733bool Display::getFloatTextureSupport(bool *filtering, bool *renderable)
734{
735 D3DDISPLAYMODE currentDisplayMode;
736 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
737
738 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
739 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
740 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
741 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
742
743 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
744 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
745 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
746 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
747
748 if (!filtering && !renderable)
749 {
750 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
751 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
752 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
753 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
754 }
755 else
756 {
757 return true;
758 }
759}
760
761bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable)
762{
763 D3DDISPLAYMODE currentDisplayMode;
764 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
765
766 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
767 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
768 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
769 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
770
771 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
772 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
773 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
774 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
775
776 if (!filtering && !renderable)
777 {
778 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
779 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
780 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
781 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
782 }
783 else
784 {
785 return true;
786 }
787}
788
daniel@transgaming.comed828e52010-10-15 17:57:30 +0000789bool Display::getLuminanceTextureSupport()
790{
791 D3DDISPLAYMODE currentDisplayMode;
792 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
793
794 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
795}
796
797bool Display::getLuminanceAlphaTextureSupport()
798{
799 D3DDISPLAYMODE currentDisplayMode;
800 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
801
802 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
803}
804
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000805D3DPOOL Display::getBufferPool(DWORD usage) const
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000806{
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000807 if (mD3d9Ex != NULL)
daniel@transgaming.comee04e452011-01-08 05:46:27 +0000808 {
809 return D3DPOOL_DEFAULT;
810 }
811 else
812 {
813 if (!(usage & D3DUSAGE_DYNAMIC))
814 {
815 return D3DPOOL_MANAGED;
816 }
817 }
818
819 return D3DPOOL_DEFAULT;
daniel@transgaming.com37b141e2011-01-08 05:46:13 +0000820}
821
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000822bool Display::getEventQuerySupport()
823{
824 IDirect3DQuery9 *query;
825 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
826 if (SUCCEEDED(result))
827 {
828 query->Release();
829 }
830
831 return result != D3DERR_NOTAVAILABLE;
832}
833
834D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
835{
836 D3DPRESENT_PARAMETERS presentParameters = {0};
837
838 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
839 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
840 presentParameters.BackBufferCount = 1;
841 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
842 presentParameters.BackBufferWidth = 1;
843 presentParameters.BackBufferHeight = 1;
844 presentParameters.EnableAutoDepthStencil = FALSE;
845 presentParameters.Flags = 0;
846 presentParameters.hDeviceWindow = mDeviceWindow;
847 presentParameters.MultiSampleQuality = 0;
848 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
849 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
850 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
851 presentParameters.Windowed = TRUE;
852
853 return presentParameters;
854}
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000855
856void Display::initExtensionString()
857{
858 mExtensionString += "EGL_ANGLE_query_surface_pointer ";
859
860 if (isD3d9ExDevice()) {
861 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
daniel@transgaming.com2b720c92011-05-13 16:05:22 +0000862 mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000863 }
864
865 std::string::size_type end = mExtensionString.find_last_not_of(' ');
866 if (end != std::string::npos)
867 {
868 mExtensionString.resize(end+1);
869 }
870}
871
872const char *Display::getExtensionString() const
873{
874 return mExtensionString.c_str();
875}
876
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000877// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
878// We test this using D3D9 by checking support for the R16F format.
879bool Display::getVertexTextureSupport() const
880{
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000881 if (!isInitialized() || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
882 {
883 return false;
884 }
885
886 D3DDISPLAYMODE currentDisplayMode;
887 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
888
889 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
890
891 return SUCCEEDED(result);
892}
893
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +0000894bool Display::getNonPower2TextureSupport() const
895{
896 return !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
897 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
898 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
899}
900
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000901}