blob: 28c0935a2f04920167b995ff9975508bd794b0ed [file] [log] [blame]
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001//
daniel@transgaming.comc6f7f9d2012-01-27 15:40:00 +00002// Copyright (c) 2002-2012 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>
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000014#include <map>
daniel@transgaming.come979ead2010-09-23 18:03:14 +000015#include <vector>
16
17#include "common/debug.h"
jbauman@chromium.org06d7a752011-04-30 01:02:52 +000018#include "libGLESv2/mathutil.h"
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +000019#include "libGLESv2/utilities.h"
daniel@transgaming.come979ead2010-09-23 18:03:14 +000020
21#include "libEGL/main.h"
22
baustin@google.com250f06c2011-06-06 16:59:53 +000023// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
24#define REF_RAST 0
25
26// The "Debug This Pixel..." feature in PIX often fails when using the
27// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7
28// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file.
29#if !defined(ANGLE_ENABLE_D3D9EX)
30// Enables use of the IDirect3D9Ex interface, when available
31#define ANGLE_ENABLE_D3D9EX 1
32#endif // !defined(ANGLE_ENABLE_D3D9EX)
daniel@transgaming.come979ead2010-09-23 18:03:14 +000033
34namespace egl
35{
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000036namespace
37{
38 typedef std::map<EGLNativeDisplayType, Display*> DisplayMap;
39 DisplayMap displays;
40}
41
42egl::Display *Display::getDisplay(EGLNativeDisplayType displayId)
43{
44 if (displays.find(displayId) != displays.end())
45 {
46 return displays[displayId];
47 }
48
49 egl::Display *display = NULL;
50
51 if (displayId == EGL_DEFAULT_DISPLAY)
52 {
53 display = new egl::Display(displayId, (HDC)NULL, false);
54 }
55 else if (displayId == EGL_SOFTWARE_DISPLAY_ANGLE)
56 {
57 display = new egl::Display(displayId, (HDC)NULL, true);
58 }
59 else
60 {
61 // FIXME: Check if displayId is a valid display device context
62
63 display = new egl::Display(displayId, (HDC)displayId, false);
64 }
65
66 displays[displayId] = display;
67 return display;
68}
69
70Display::Display(EGLNativeDisplayType displayId, HDC deviceContext, bool software) : mDc(deviceContext)
daniel@transgaming.come979ead2010-09-23 18:03:14 +000071{
72 mD3d9Module = NULL;
73
74 mD3d9 = NULL;
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000075 mD3d9Ex = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +000076 mDevice = NULL;
apatrick@chromium.org9e83b592011-02-10 22:04:34 +000077 mDeviceEx = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +000078 mDeviceWindow = NULL;
79
80 mAdapter = D3DADAPTER_DEFAULT;
81
82 #if REF_RAST == 1 || defined(FORCE_REF_RAST)
83 mDeviceType = D3DDEVTYPE_REF;
84 #else
85 mDeviceType = D3DDEVTYPE_HAL;
86 #endif
87
88 mMinSwapInterval = 1;
89 mMaxSwapInterval = 1;
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000090 mSoftwareDevice = software;
91 mDisplayId = displayId;
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +000092 mDeviceLost = false;
daniel@transgaming.come979ead2010-09-23 18:03:14 +000093}
94
95Display::~Display()
96{
97 terminate();
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000098
99 DisplayMap::iterator thisDisplay = displays.find(mDisplayId);
100
101 if (thisDisplay != displays.end())
102 {
103 displays.erase(thisDisplay);
104 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000105}
106
107bool Display::initialize()
108{
109 if (isInitialized())
110 {
111 return true;
112 }
113
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +0000114 if (mSoftwareDevice)
115 {
116 mD3d9Module = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
117 }
118 else
119 {
120 mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
121 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000122 if (mD3d9Module == NULL)
123 {
124 terminate();
125 return false;
126 }
127
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000128 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
129 Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
130
131 // Use Direct3D9Ex if available. Among other things, this version is less
132 // inclined to report a lost context, for example when the user switches
133 // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
baustin@google.com250f06c2011-06-06 16:59:53 +0000134 if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000135 {
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000136 ASSERT(mD3d9Ex);
137 mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000138 ASSERT(mD3d9);
139 }
140 else
141 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000142 mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000143 }
144
145 if (mD3d9)
146 {
147 if (mDc != NULL)
148 {
149 // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
150 }
151
152 HRESULT result;
153
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000154 // Give up on getting device caps after about one second.
155 for (int i = 0; i < 10; ++i)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000156 {
157 result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000158
159 if (SUCCEEDED(result))
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000160 {
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000161 break;
162 }
163 else if (result == D3DERR_NOTAVAILABLE)
164 {
165 Sleep(100); // Give the driver some time to initialize/recover
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000166 }
167 else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
168 {
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000169 terminate();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000170 return error(EGL_BAD_ALLOC, false);
171 }
172 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000173
174 if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
175 {
176 terminate();
177 return error(EGL_NOT_INITIALIZED, false);
178 }
179
apatrick@chromium.org1c768012010-10-07 00:35:24 +0000180 // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
181 // This is required by Texture2D::convertToRenderTarget.
182 if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
183 {
184 terminate();
185 return error(EGL_NOT_INITIALIZED, false);
186 }
187
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000188 mMinSwapInterval = 4;
189 mMaxSwapInterval = 0;
190
191 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {mMinSwapInterval = std::min(mMinSwapInterval, 0); mMaxSwapInterval = std::max(mMaxSwapInterval, 0);}
192 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) {mMinSwapInterval = std::min(mMinSwapInterval, 1); mMaxSwapInterval = std::max(mMaxSwapInterval, 1);}
193 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) {mMinSwapInterval = std::min(mMinSwapInterval, 2); mMaxSwapInterval = std::max(mMaxSwapInterval, 2);}
194 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);}
195 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);}
196
jbauman@chromium.org03208d52011-06-15 01:15:24 +0000197 mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
198
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000199 const D3DFORMAT renderTargetFormats[] =
200 {
201 D3DFMT_A1R5G5B5,
202 // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
203 D3DFMT_A8R8G8B8,
204 D3DFMT_R5G6B5,
daniel@transgaming.com73a5db62010-10-15 17:58:13 +0000205 // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000206 D3DFMT_X8R8G8B8
207 };
208
209 const D3DFORMAT depthStencilFormats[] =
210 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000211 D3DFMT_UNKNOWN,
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000212 // D3DFMT_D16_LOCKABLE,
213 D3DFMT_D32,
214 // D3DFMT_D15S1,
215 D3DFMT_D24S8,
216 D3DFMT_D24X8,
217 // D3DFMT_D24X4S4,
218 D3DFMT_D16,
219 // D3DFMT_D32F_LOCKABLE,
220 // D3DFMT_D24FS8
221 };
222
223 D3DDISPLAYMODE currentDisplayMode;
224 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
225
226 ConfigSet configSet;
227
228 for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++)
229 {
230 D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex];
231
232 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
233
234 if (SUCCEEDED(result))
235 {
236 for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++)
237 {
238 D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex];
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000239 HRESULT result = D3D_OK;
240
241 if(depthStencilFormat != D3DFMT_UNKNOWN)
242 {
243 result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
244 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000245
246 if (SUCCEEDED(result))
247 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000248 if(depthStencilFormat != D3DFMT_UNKNOWN)
249 {
250 result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
251 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000252
253 if (SUCCEEDED(result))
254 {
255 // FIXME: enumerate multi-sampling
256
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000257 configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0,
258 mDeviceCaps.MaxTextureWidth, mDeviceCaps.MaxTextureHeight);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000259 }
260 }
261 }
262 }
263 }
264
265 // Give the sorted configs a unique ID and store them internally
266 EGLint index = 1;
267 for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
268 {
269 Config configuration = *config;
270 configuration.mConfigID = index;
271 index++;
272
273 mConfigSet.mSet.insert(configuration);
274 }
275 }
276
277 if (!isInitialized())
278 {
279 terminate();
280
281 return false;
282 }
283
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000284 initExtensionString();
285
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000286 static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
287 static const TCHAR className[] = TEXT("STATIC");
288
289 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
290
apatrick@chromium.orgcca2b702012-02-08 00:59:46 +0000291 if (!createDevice())
292 {
293 terminate();
294 return false;
295 }
296
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000297 return true;
298}
299
300void Display::terminate()
301{
302 while (!mSurfaceSet.empty())
303 {
304 destroySurface(*mSurfaceSet.begin());
305 }
306
307 while (!mContextSet.empty())
308 {
309 destroyContext(*mContextSet.begin());
310 }
311
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000312 while (!mEventQueryPool.empty())
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000313 {
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000314 mEventQueryPool.back()->Release();
315 mEventQueryPool.pop_back();
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000316 }
317
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000318 if (mDevice)
319 {
320 // If the device is lost, reset it first to prevent leaving the driver in an unstable state
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000321 if (testDeviceLost())
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000322 {
323 resetDevice();
324 }
325
326 mDevice->Release();
327 mDevice = NULL;
328 }
329
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000330 if (mDeviceEx)
331 {
332 mDeviceEx->Release();
333 mDeviceEx = NULL;
334 }
335
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000336 if (mD3d9)
337 {
338 mD3d9->Release();
339 mD3d9 = NULL;
340 }
341
342 if (mDeviceWindow)
343 {
344 DestroyWindow(mDeviceWindow);
345 mDeviceWindow = NULL;
346 }
347
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000348 if (mD3d9Ex)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000349 {
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000350 mD3d9Ex->Release();
351 mD3d9Ex = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000352 }
353
354 if (mD3d9Module)
355 {
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000356 mD3d9Module = NULL;
357 }
358}
359
360void Display::startScene()
361{
362 if (!mSceneStarted)
363 {
364 long result = mDevice->BeginScene();
kbr@chromium.org1a2cd262011-07-08 17:30:18 +0000365 if (SUCCEEDED(result)) {
366 // This is defensive checking against the device being
367 // lost at unexpected times.
368 mSceneStarted = true;
369 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000370 }
371}
372
373void Display::endScene()
374{
375 if (mSceneStarted)
376 {
kbr@chromium.org1a2cd262011-07-08 17:30:18 +0000377 // EndScene can fail if the device was lost, for example due
378 // to a TDR during a draw call.
379 mDevice->EndScene();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000380 mSceneStarted = false;
381 }
382}
383
384bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
385{
386 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
387}
388
389bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
390{
391 const egl::Config *configuration = mConfigSet.get(config);
392
393 switch (attribute)
394 {
395 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
396 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
397 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
398 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
399 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
400 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
401 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
402 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
403 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
404 case EGL_LEVEL: *value = configuration->mLevel; break;
405 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
406 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
407 case EGL_SAMPLES: *value = configuration->mSamples; break;
408 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
409 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
410 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
411 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
412 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
413 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
414 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
415 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
416 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
417 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
418 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
419 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
420 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
421 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
422 case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
423 case EGL_CONFORMANT: *value = configuration->mConformant; break;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000424 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
425 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
426 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000427 default:
428 return false;
429 }
430
431 return true;
432}
433
434bool Display::createDevice()
435{
436 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
437 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
438
439 HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
440
441 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
442 {
443 return error(EGL_BAD_ALLOC, false);
444 }
445
446 if (FAILED(result))
447 {
448 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
449
450 if (FAILED(result))
451 {
452 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
453 return error(EGL_BAD_ALLOC, false);
454 }
455 }
456
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000457 if (mD3d9Ex)
458 {
459 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
460 ASSERT(SUCCEEDED(result));
461 }
462
daniel@transgaming.come19d8322011-12-13 17:30:48 +0000463 initializeDevice();
464
465 return true;
466}
467
468// do any one-time device initialization
469// NOTE: this is also needed after a device lost/reset
470// to reset the scene status and ensure the default states are reset.
471void Display::initializeDevice()
472{
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000473 // Permanent non-default states
474 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
daniel@transgaming.com7a2fdc92011-11-24 22:34:09 +0000475 mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000476
477 mSceneStarted = false;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000478}
479
480bool Display::resetDevice()
481{
482 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000483
daniel@transgaming.com10435352011-11-09 17:44:21 +0000484 HRESULT result = D3D_OK;
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000485 bool lost = testDeviceLost();
daniel@transgaming.com10435352011-11-09 17:44:21 +0000486 int attempts = 3;
daniel@transgaming.com94910c92011-11-09 17:44:15 +0000487
daniel@transgaming.com10435352011-11-09 17:44:21 +0000488 while (lost && attempts > 0)
daniel@transgaming.com94910c92011-11-09 17:44:15 +0000489 {
daniel@transgaming.com10435352011-11-09 17:44:21 +0000490 if (mDeviceEx)
491 {
492 Sleep(500); // Give the graphics driver some CPU time
493 result = mDeviceEx->ResetEx(&presentParameters, NULL);
494 }
495 else
496 {
497 result = mDevice->TestCooperativeLevel();
498
499 while (result == D3DERR_DEVICELOST)
500 {
501 Sleep(100); // Give the graphics driver some CPU time
502 result = mDevice->TestCooperativeLevel();
503 }
504
505 if (result == D3DERR_DEVICENOTRESET)
506 {
507 result = mDevice->Reset(&presentParameters);
508 }
509 }
510
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000511 lost = testDeviceLost();
daniel@transgaming.com10435352011-11-09 17:44:21 +0000512 attempts --;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000513 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000514
515 if (FAILED(result))
516 {
daniel@transgaming.com10435352011-11-09 17:44:21 +0000517 ERR("Reset/ResetEx failed multiple times: 0x%08X", result);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000518 return error(EGL_BAD_ALLOC, false);
519 }
520
daniel@transgaming.come19d8322011-12-13 17:30:48 +0000521 // reset device defaults
522 initializeDevice();
523
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000524 return true;
525}
526
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000527EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000528{
529 const Config *configuration = mConfigSet.get(config);
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000530 EGLint postSubBufferSupported = EGL_FALSE;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000531
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000532 if (attribList)
533 {
534 while (*attribList != EGL_NONE)
535 {
536 switch (attribList[0])
537 {
538 case EGL_RENDER_BUFFER:
539 switch (attribList[1])
540 {
541 case EGL_BACK_BUFFER:
542 break;
543 case EGL_SINGLE_BUFFER:
544 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
545 default:
546 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
547 }
548 break;
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000549 case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
550 postSubBufferSupported = attribList[1];
551 break;
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000552 case EGL_VG_COLORSPACE:
553 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
554 case EGL_VG_ALPHA_FORMAT:
555 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
556 default:
557 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
558 }
559
560 attribList += 2;
561 }
562 }
563
564 if (hasExistingWindowSurface(window))
565 {
566 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
567 }
568
daniel@transgaming.comcf23c452011-11-09 17:47:26 +0000569 if (testDeviceLost())
570 {
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000571 if (!restoreLostDevice())
572 return EGL_NO_SURFACE;
573 }
574
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000575 Surface *surface = new Surface(this, configuration, window, postSubBufferSupported);
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000576
577 if (!surface->initialize())
578 {
579 delete surface;
580 return EGL_NO_SURFACE;
581 }
582
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000583 mSurfaceSet.insert(surface);
584
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000585 return success(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000586}
587
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000588EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000589{
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000590 EGLint width = 0, height = 0;
591 EGLenum textureFormat = EGL_NO_TEXTURE;
592 EGLenum textureTarget = EGL_NO_TEXTURE;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000593 const Config *configuration = mConfigSet.get(config);
594
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000595 if (attribList)
596 {
597 while (*attribList != EGL_NONE)
598 {
599 switch (attribList[0])
600 {
601 case EGL_WIDTH:
602 width = attribList[1];
603 break;
604 case EGL_HEIGHT:
605 height = attribList[1];
606 break;
607 case EGL_LARGEST_PBUFFER:
608 if (attribList[1] != EGL_FALSE)
609 UNIMPLEMENTED(); // FIXME
610 break;
611 case EGL_TEXTURE_FORMAT:
612 switch (attribList[1])
613 {
614 case EGL_NO_TEXTURE:
615 case EGL_TEXTURE_RGB:
616 case EGL_TEXTURE_RGBA:
617 textureFormat = attribList[1];
618 break;
619 default:
620 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
621 }
622 break;
623 case EGL_TEXTURE_TARGET:
624 switch (attribList[1])
625 {
626 case EGL_NO_TEXTURE:
627 case EGL_TEXTURE_2D:
628 textureTarget = attribList[1];
629 break;
630 default:
631 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
632 }
633 break;
634 case EGL_MIPMAP_TEXTURE:
635 if (attribList[1] != EGL_FALSE)
636 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
637 break;
638 case EGL_VG_COLORSPACE:
639 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
640 case EGL_VG_ALPHA_FORMAT:
641 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
642 default:
643 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
644 }
645
646 attribList += 2;
647 }
648 }
649
650 if (width < 0 || height < 0)
651 {
652 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
653 }
654
655 if (width == 0 || height == 0)
656 {
657 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
658 }
659
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +0000660 if (textureFormat != EGL_NO_TEXTURE && !getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000661 {
662 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
663 }
664
665 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
666 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
667 {
668 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
669 }
670
671 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
672 {
673 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
674 }
675
676 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
677 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
678 {
679 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
680 }
681
daniel@transgaming.comcf23c452011-11-09 17:47:26 +0000682 if (testDeviceLost())
683 {
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000684 if (!restoreLostDevice())
685 return EGL_NO_SURFACE;
686 }
687
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000688 Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
689
690 if (!surface->initialize())
691 {
692 delete surface;
693 return EGL_NO_SURFACE;
694 }
695
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000696 mSurfaceSet.insert(surface);
697
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000698 return success(surface);
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000699}
700
daniel@transgaming.com4ff960d2011-11-09 17:47:09 +0000701EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000702{
703 if (!mDevice)
704 {
705 if (!createDevice())
706 {
707 return NULL;
708 }
709 }
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000710 else if (testDeviceLost()) // Lost device
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000711 {
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000712 if (!restoreLostDevice())
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000713 return NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000714 }
715
716 const egl::Config *config = mConfigSet.get(configHandle);
717
daniel@transgaming.com4ff960d2011-11-09 17:47:09 +0000718 gl::Context *context = glCreateContext(config, shareContext, notifyResets, robustAccess);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000719 mContextSet.insert(context);
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000720 mDeviceLost = false;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000721
722 return context;
723}
724
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000725bool Display::restoreLostDevice()
726{
daniel@transgaming.comcf23c452011-11-09 17:47:26 +0000727 for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
728 {
729 if ((*ctx)->isResetNotificationEnabled())
730 return false; // If reset notifications have been requested, application must delete all contexts first
731 }
732
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000733 // Release surface resources to make the Reset() succeed
734 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
735 {
736 (*surface)->release();
737 }
738
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000739 while (!mEventQueryPool.empty())
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000740 {
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000741 mEventQueryPool.back()->Release();
742 mEventQueryPool.pop_back();
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000743 }
744
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000745 if (!resetDevice())
746 {
747 return false;
748 }
749
750 // Restore any surfaces that may have been lost
751 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
752 {
753 (*surface)->resetSwapChain();
754 }
755
756 return true;
757}
758
759
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000760void Display::destroySurface(egl::Surface *surface)
761{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000762 delete surface;
763 mSurfaceSet.erase(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000764}
765
766void Display::destroyContext(gl::Context *context)
767{
768 glDestroyContext(context);
769 mContextSet.erase(context);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000770}
771
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000772void Display::notifyDeviceLost()
773{
774 for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++)
775 {
776 (*context)->markContextLost();
777 }
778 mDeviceLost = true;
779 error(EGL_CONTEXT_LOST);
780}
781
782bool Display::isDeviceLost()
783{
784 return mDeviceLost;
785}
786
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000787bool Display::isInitialized() const
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000788{
789 return mD3d9 != NULL && mConfigSet.size() > 0;
790}
791
792bool Display::isValidConfig(EGLConfig config)
793{
794 return mConfigSet.get(config) != NULL;
795}
796
797bool Display::isValidContext(gl::Context *context)
798{
799 return mContextSet.find(context) != mContextSet.end();
800}
801
802bool Display::isValidSurface(egl::Surface *surface)
803{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000804 return mSurfaceSet.find(surface) != mSurfaceSet.end();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000805}
806
807bool Display::hasExistingWindowSurface(HWND window)
808{
809 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
810 {
811 if ((*surface)->getWindowHandle() == window)
812 {
813 return true;
814 }
815 }
816
817 return false;
818}
819
820EGLint Display::getMinSwapInterval()
821{
822 return mMinSwapInterval;
823}
824
825EGLint Display::getMaxSwapInterval()
826{
827 return mMaxSwapInterval;
828}
829
830IDirect3DDevice9 *Display::getDevice()
831{
832 if (!mDevice)
833 {
834 if (!createDevice())
835 {
836 return NULL;
837 }
838 }
839
840 return mDevice;
841}
842
843D3DCAPS9 Display::getDeviceCaps()
844{
845 return mDeviceCaps;
846}
847
jbauman@chromium.org03208d52011-06-15 01:15:24 +0000848D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier()
849{
850 return &mAdapterIdentifier;
851}
852
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000853bool Display::testDeviceLost()
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000854{
855 if (mDeviceEx)
856 {
857 return FAILED(mDeviceEx->CheckDeviceState(NULL));
858 }
daniel@transgaming.com17f548c2011-11-09 17:47:02 +0000859 else if (mDevice)
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000860 {
861 return FAILED(mDevice->TestCooperativeLevel());
862 }
daniel@transgaming.comfe4b0c92011-09-13 00:53:11 +0000863
864 return false; // No device yet, so no reset required
apatrick@chromium.org9e83b592011-02-10 22:04:34 +0000865}
866
daniel@transgaming.com17f548c2011-11-09 17:47:02 +0000867bool Display::testDeviceResettable()
868{
869 HRESULT status = D3D_OK;
870
871 if (mDeviceEx)
872 {
873 status = mDeviceEx->CheckDeviceState(NULL);
874 }
875 else if (mDevice)
876 {
877 status = mDevice->TestCooperativeLevel();
878 }
879
880 switch (status)
881 {
882 case D3DERR_DEVICENOTRESET:
883 case D3DERR_DEVICEHUNG:
884 return true;
885 default:
886 return false;
887 }
888}
889
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000890void Display::sync(bool block)
891{
892 HRESULT result;
893
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000894 IDirect3DQuery9* query = allocateEventQuery();
895 if (!query)
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000896 {
897 return;
898 }
899
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000900 result = query->Issue(D3DISSUE_END);
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000901 ASSERT(SUCCEEDED(result));
902
903 do
904 {
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000905 result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000906
907 if(block && result == S_FALSE)
908 {
909 // Keep polling, but allow other threads to do something useful first
910 Sleep(0);
911 // explicitly check for device loss
912 // some drivers seem to return S_FALSE even if the device is lost
913 // instead of D3DERR_DEVICELOST like they should
914 if (testDeviceLost())
915 {
916 result = D3DERR_DEVICELOST;
917 }
918 }
919 }
920 while(block && result == S_FALSE);
921
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000922 freeEventQuery(query);
923
daniel@transgaming.com2678b342012-01-18 16:29:40 +0000924 if (isDeviceLostError(result))
925 {
926 notifyDeviceLost();
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000927 }
928}
929
930IDirect3DQuery9* Display::allocateEventQuery()
931{
932 IDirect3DQuery9 *query = NULL;
933
934 if (mEventQueryPool.empty())
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000935 {
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000936 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
937 ASSERT(SUCCEEDED(result));
938 }
939 else
940 {
941 query = mEventQueryPool.back();
942 mEventQueryPool.pop_back();
943 }
944
945 return query;
946}
947
948void Display::freeEventQuery(IDirect3DQuery9* query)
949{
950 if (mEventQueryPool.size() > 1000)
951 {
952 query->Release();
953 }
954 else
955 {
956 mEventQueryPool.push_back(query);
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000957 }
958}
959
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000960void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
961{
962 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
963 {
964 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
965 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
966
967 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
968 }
969}
970
gman@chromium.org50c526d2011-08-10 05:19:44 +0000971bool Display::getDXT1TextureSupport()
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000972{
973 D3DDISPLAYMODE currentDisplayMode;
974 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
975
976 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
977}
978
gman@chromium.org50c526d2011-08-10 05:19:44 +0000979bool Display::getDXT3TextureSupport()
980{
981 D3DDISPLAYMODE currentDisplayMode;
982 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
983
984 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3));
985}
986
987bool Display::getDXT5TextureSupport()
988{
989 D3DDISPLAYMODE currentDisplayMode;
990 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
991
992 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5));
993}
994
daniel@transgaming.com1c49f792012-05-31 01:14:02 +0000995// we use INTZ for depth textures in Direct3D9
996// we also want NULL texture support to ensure the we can make depth-only FBOs
997// see http://aras-p.info/texts/D3D9GPUHacks.html
998bool Display::getDepthTextureSupport() const
999{
1000 D3DDISPLAYMODE currentDisplayMode;
1001 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
1002
1003 bool intz = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
1004 D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ));
1005 bool null = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
1006 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL));
1007
1008 return intz && null;
1009}
1010
daniel@transgaming.combbeffbb2011-11-09 17:46:11 +00001011bool Display::getFloat32TextureSupport(bool *filtering, bool *renderable)
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001012{
1013 D3DDISPLAYMODE currentDisplayMode;
1014 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
1015
1016 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
1017 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
1018 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
1019 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
1020
1021 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
1022 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
1023 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
1024 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
1025
daniel@transgaming.combb5223d2012-01-24 13:38:10 +00001026 if (!*filtering && !*renderable)
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001027 {
1028 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
1029 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
1030 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
1031 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
1032 }
1033 else
1034 {
1035 return true;
1036 }
1037}
1038
daniel@transgaming.combbeffbb2011-11-09 17:46:11 +00001039bool Display::getFloat16TextureSupport(bool *filtering, bool *renderable)
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001040{
1041 D3DDISPLAYMODE currentDisplayMode;
1042 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
1043
1044 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
1045 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
1046 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
1047 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
1048
1049 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
1050 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
1051 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
1052 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
1053
daniel@transgaming.combb5223d2012-01-24 13:38:10 +00001054 if (!*filtering && !*renderable)
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001055 {
1056 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
1057 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
1058 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
1059 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
1060 }
1061 else
1062 {
1063 return true;
1064 }
1065}
1066
daniel@transgaming.comed828e52010-10-15 17:57:30 +00001067bool Display::getLuminanceTextureSupport()
1068{
1069 D3DDISPLAYMODE currentDisplayMode;
1070 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
1071
1072 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
1073}
1074
1075bool Display::getLuminanceAlphaTextureSupport()
1076{
1077 D3DDISPLAYMODE currentDisplayMode;
1078 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
1079
1080 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
1081}
1082
daniel@transgaming.comee04e452011-01-08 05:46:27 +00001083D3DPOOL Display::getBufferPool(DWORD usage) const
daniel@transgaming.com37b141e2011-01-08 05:46:13 +00001084{
apatrick@chromium.org9e83b592011-02-10 22:04:34 +00001085 if (mD3d9Ex != NULL)
daniel@transgaming.comee04e452011-01-08 05:46:27 +00001086 {
1087 return D3DPOOL_DEFAULT;
1088 }
1089 else
1090 {
1091 if (!(usage & D3DUSAGE_DYNAMIC))
1092 {
1093 return D3DPOOL_MANAGED;
1094 }
1095 }
1096
1097 return D3DPOOL_DEFAULT;
daniel@transgaming.com37b141e2011-01-08 05:46:13 +00001098}
1099
daniel@transgaming.com59580a32011-11-12 04:23:44 +00001100D3DPOOL Display::getTexturePool(bool renderable) const
1101{
1102 if (mD3d9Ex != NULL)
1103 {
1104 return D3DPOOL_DEFAULT;
1105 }
1106 else
1107 {
1108 if (!renderable)
1109 {
1110 return D3DPOOL_MANAGED;
1111 }
1112 }
1113
1114 return D3DPOOL_DEFAULT;
1115}
1116
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001117bool Display::getEventQuerySupport()
1118{
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +00001119 IDirect3DQuery9 *query = allocateEventQuery();
1120 if (query)
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001121 {
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +00001122 freeEventQuery(query);
1123 return true;
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001124 }
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +00001125 else
1126 {
1127 return false;
1128 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001129}
1130
1131D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
1132{
1133 D3DPRESENT_PARAMETERS presentParameters = {0};
1134
1135 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
1136 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
1137 presentParameters.BackBufferCount = 1;
1138 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
1139 presentParameters.BackBufferWidth = 1;
1140 presentParameters.BackBufferHeight = 1;
1141 presentParameters.EnableAutoDepthStencil = FALSE;
1142 presentParameters.Flags = 0;
1143 presentParameters.hDeviceWindow = mDeviceWindow;
1144 presentParameters.MultiSampleQuality = 0;
1145 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
1146 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
1147 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
1148 presentParameters.Windowed = TRUE;
1149
1150 return presentParameters;
1151}
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +00001152
1153void Display::initExtensionString()
1154{
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +00001155 HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
daniel@transgaming.com1a1fe242011-09-26 18:25:45 +00001156
1157 mExtensionString = "";
1158
daniel@transgaming.com8747f182011-11-09 17:50:38 +00001159 // Multi-vendor (EXT) extensions
1160 mExtensionString += "EGL_EXT_create_context_robustness ";
1161
1162 // ANGLE-specific extensions
jbauman@chromium.org6c762d02012-02-03 23:31:53 +00001163 if (shareHandleSupported())
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +00001164 {
daniel@transgaming.com1a1fe242011-09-26 18:25:45 +00001165 mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
1166 }
1167
1168 mExtensionString += "EGL_ANGLE_query_surface_pointer ";
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +00001169
1170 if (swiftShader)
1171 {
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +00001172 mExtensionString += "EGL_ANGLE_software_display ";
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +00001173 }
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +00001174
jbauman@chromium.org6c762d02012-02-03 23:31:53 +00001175 if (shareHandleSupported())
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +00001176 {
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +00001177 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
1178 }
1179
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +00001180 mExtensionString += "EGL_NV_post_sub_buffer";
1181
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +00001182 std::string::size_type end = mExtensionString.find_last_not_of(' ');
1183 if (end != std::string::npos)
1184 {
1185 mExtensionString.resize(end+1);
1186 }
1187}
1188
1189const char *Display::getExtensionString() const
1190{
1191 return mExtensionString.c_str();
1192}
1193
jbauman@chromium.org6c762d02012-02-03 23:31:53 +00001194bool Display::shareHandleSupported() const
1195{
1196 // PIX doesn't seem to support using share handles, so disable them.
1197 return isD3d9ExDevice() && !gl::perfActive();
1198}
1199
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +00001200// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
1201// We test this using D3D9 by checking support for the R16F format.
1202bool Display::getVertexTextureSupport() const
1203{
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +00001204 if (!isInitialized() || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
1205 {
1206 return false;
1207 }
1208
1209 D3DDISPLAYMODE currentDisplayMode;
1210 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
1211
1212 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
1213
1214 return SUCCEEDED(result);
1215}
1216
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001217bool Display::getNonPower2TextureSupport() const
1218{
1219 return !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
1220 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
1221 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
1222}
1223
daniel@transgaming.com86bdb822012-01-20 18:24:39 +00001224bool Display::getOcclusionQuerySupport() const
1225{
1226 if (!isInitialized())
1227 {
1228 return false;
1229 }
1230
1231 IDirect3DQuery9 *query = NULL;
1232 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query);
1233
1234 if (SUCCEEDED(result) && query)
1235 {
1236 query->Release();
1237 return true;
1238 }
1239 else
1240 {
1241 return false;
1242 }
1243}
1244
daniel@transgaming.comc6f7f9d2012-01-27 15:40:00 +00001245bool Display::getInstancingSupport() const
1246{
1247 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
1248}
1249
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +00001250}