1 //
2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3 // 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"
17 
18 #include "libEGL/main.h"
19 
20 #define REF_RAST 0        // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
21 #define ENABLE_D3D9EX 1   // Enables use of the IDirect3D9Ex interface, when available
22 
23 namespace egl
24 {
Display(HDC deviceContext)25 Display::Display(HDC deviceContext) : mDc(deviceContext)
26 {
27     mD3d9Module = NULL;
28 
29     mD3d9 = NULL;
30     mD3d9ex = NULL;
31     mDevice = NULL;
32     mDeviceWindow = NULL;
33 
34     mAdapter = D3DADAPTER_DEFAULT;
35 
36     #if REF_RAST == 1 || defined(FORCE_REF_RAST)
37         mDeviceType = D3DDEVTYPE_REF;
38     #else
39         mDeviceType = D3DDEVTYPE_HAL;
40     #endif
41 
42     mMinSwapInterval = 1;
43     mMaxSwapInterval = 1;
44 }
45 
~Display()46 Display::~Display()
47 {
48     terminate();
49 }
50 
initialize()51 bool Display::initialize()
52 {
53     if (isInitialized())
54     {
55         return true;
56     }
57 
58     mD3d9Module = LoadLibrary(TEXT("d3d9.dll"));
59     if (mD3d9Module == NULL)
60     {
61         terminate();
62         return false;
63     }
64 
65     typedef IDirect3D9* (WINAPI *Direct3DCreate9Func)(UINT);
66     Direct3DCreate9Func Direct3DCreate9Ptr = reinterpret_cast<Direct3DCreate9Func>(GetProcAddress(mD3d9Module, "Direct3DCreate9"));
67 
68     if (Direct3DCreate9Ptr == NULL)
69     {
70         terminate();
71         return false;
72     }
73 
74     typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
75     Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
76 
77     // Use Direct3D9Ex if available. Among other things, this version is less
78     // inclined to report a lost context, for example when the user switches
79     // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
80     if (ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9ex)))
81     {
82         ASSERT(mD3d9ex);
83         mD3d9ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
84         ASSERT(mD3d9);
85     }
86     else
87     {
88         mD3d9 = Direct3DCreate9Ptr(D3D_SDK_VERSION);
89     }
90 
91     if (mD3d9)
92     {
93         if (mDc != NULL)
94         {
95         //  UNIMPLEMENTED();   // FIXME: Determine which adapter index the device context corresponds to
96         }
97 
98         HRESULT result;
99 
100         // Give up on getting device caps after about one second.
101         for (int i = 0; i < 10; ++i)
102         {
103             result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
104 
105             if (SUCCEEDED(result))
106             {
107                 break;
108             }
109             else if (result == D3DERR_NOTAVAILABLE)
110             {
111                 Sleep(100);   // Give the driver some time to initialize/recover
112             }
113             else if (FAILED(result))   // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
114             {
115                 terminate();
116                 return error(EGL_BAD_ALLOC, false);
117             }
118         }
119 
120         if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
121         {
122             terminate();
123             return error(EGL_NOT_INITIALIZED, false);
124         }
125 
126         // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
127         // This is required by Texture2D::convertToRenderTarget.
128         if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
129         {
130             terminate();
131             return error(EGL_NOT_INITIALIZED, false);
132         }
133 
134         mMinSwapInterval = 4;
135         mMaxSwapInterval = 0;
136 
137         if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {mMinSwapInterval = std::min(mMinSwapInterval, 0); mMaxSwapInterval = std::max(mMaxSwapInterval, 0);}
138         if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)       {mMinSwapInterval = std::min(mMinSwapInterval, 1); mMaxSwapInterval = std::max(mMaxSwapInterval, 1);}
139         if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)       {mMinSwapInterval = std::min(mMinSwapInterval, 2); mMaxSwapInterval = std::max(mMaxSwapInterval, 2);}
140         if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE)     {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);}
141         if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR)      {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);}
142 
143         const D3DFORMAT renderTargetFormats[] =
144         {
145             D3DFMT_A1R5G5B5,
146         //  D3DFMT_A2R10G10B10,   // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
147             D3DFMT_A8R8G8B8,
148             D3DFMT_R5G6B5,
149         //  D3DFMT_X1R5G5B5,      // Has no compatible OpenGL ES renderbuffer format
150             D3DFMT_X8R8G8B8
151         };
152 
153         const D3DFORMAT depthStencilFormats[] =
154         {
155         //  D3DFMT_D16_LOCKABLE,
156             D3DFMT_D32,
157         //  D3DFMT_D15S1,
158             D3DFMT_D24S8,
159             D3DFMT_D24X8,
160         //  D3DFMT_D24X4S4,
161             D3DFMT_D16,
162         //  D3DFMT_D32F_LOCKABLE,
163         //  D3DFMT_D24FS8
164         };
165 
166         D3DDISPLAYMODE currentDisplayMode;
167         mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
168 
169         ConfigSet configSet;
170 
171         for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++)
172         {
173             D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex];
174 
175             HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
176 
177             if (SUCCEEDED(result))
178             {
179                 for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++)
180                 {
181                     D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex];
182                     HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
183 
184                     if (SUCCEEDED(result))
185                     {
186                         HRESULT result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
187 
188                         if (SUCCEEDED(result))
189                         {
190                             // FIXME: enumerate multi-sampling
191 
192                             configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0);
193                         }
194                     }
195                 }
196             }
197         }
198 
199         // Give the sorted configs a unique ID and store them internally
200         EGLint index = 1;
201         for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
202         {
203             Config configuration = *config;
204             configuration.mConfigID = index;
205             index++;
206 
207             mConfigSet.mSet.insert(configuration);
208         }
209     }
210 
211     if (!isInitialized())
212     {
213         terminate();
214 
215         return false;
216     }
217 
218     static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
219     static const TCHAR className[] = TEXT("STATIC");
220 
221     mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
222 
223     return true;
224 }
225 
terminate()226 void Display::terminate()
227 {
228     while (!mSurfaceSet.empty())
229     {
230         destroySurface(*mSurfaceSet.begin());
231     }
232 
233     while (!mContextSet.empty())
234     {
235         destroyContext(*mContextSet.begin());
236     }
237 
238     if (mDevice)
239     {
240         // If the device is lost, reset it first to prevent leaving the driver in an unstable state
241         if (FAILED(mDevice->TestCooperativeLevel()))
242         {
243             resetDevice();
244         }
245 
246         mDevice->Release();
247         mDevice = NULL;
248     }
249 
250     if (mD3d9)
251     {
252         mD3d9->Release();
253         mD3d9 = NULL;
254     }
255 
256     if (mDeviceWindow)
257     {
258         DestroyWindow(mDeviceWindow);
259         mDeviceWindow = NULL;
260     }
261 
262     if (mD3d9ex)
263     {
264         mD3d9ex->Release();
265         mD3d9ex = NULL;
266     }
267 
268     if (mD3d9Module)
269     {
270         FreeLibrary(mD3d9Module);
271         mD3d9Module = NULL;
272     }
273 }
274 
startScene()275 void Display::startScene()
276 {
277     if (!mSceneStarted)
278     {
279         long result = mDevice->BeginScene();
280         ASSERT(SUCCEEDED(result));
281         mSceneStarted = true;
282     }
283 }
284 
endScene()285 void Display::endScene()
286 {
287     if (mSceneStarted)
288     {
289         long result = mDevice->EndScene();
290         ASSERT(SUCCEEDED(result));
291         mSceneStarted = false;
292     }
293 }
294 
getConfigs(EGLConfig * configs,const EGLint * attribList,EGLint configSize,EGLint * numConfig)295 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
296 {
297     return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
298 }
299 
getConfigAttrib(EGLConfig config,EGLint attribute,EGLint * value)300 bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
301 {
302     const egl::Config *configuration = mConfigSet.get(config);
303 
304     switch (attribute)
305     {
306       case EGL_BUFFER_SIZE:               *value = configuration->mBufferSize;             break;
307       case EGL_ALPHA_SIZE:                *value = configuration->mAlphaSize;              break;
308       case EGL_BLUE_SIZE:                 *value = configuration->mBlueSize;               break;
309       case EGL_GREEN_SIZE:                *value = configuration->mGreenSize;              break;
310       case EGL_RED_SIZE:                  *value = configuration->mRedSize;                break;
311       case EGL_DEPTH_SIZE:                *value = configuration->mDepthSize;              break;
312       case EGL_STENCIL_SIZE:              *value = configuration->mStencilSize;            break;
313       case EGL_CONFIG_CAVEAT:             *value = configuration->mConfigCaveat;           break;
314       case EGL_CONFIG_ID:                 *value = configuration->mConfigID;               break;
315       case EGL_LEVEL:                     *value = configuration->mLevel;                  break;
316       case EGL_NATIVE_RENDERABLE:         *value = configuration->mNativeRenderable;       break;
317       case EGL_NATIVE_VISUAL_TYPE:        *value = configuration->mNativeVisualType;       break;
318       case EGL_SAMPLES:                   *value = configuration->mSamples;                break;
319       case EGL_SAMPLE_BUFFERS:            *value = configuration->mSampleBuffers;          break;
320       case EGL_SURFACE_TYPE:              *value = configuration->mSurfaceType;            break;
321       case EGL_TRANSPARENT_TYPE:          *value = configuration->mTransparentType;        break;
322       case EGL_TRANSPARENT_BLUE_VALUE:    *value = configuration->mTransparentBlueValue;   break;
323       case EGL_TRANSPARENT_GREEN_VALUE:   *value = configuration->mTransparentGreenValue;  break;
324       case EGL_TRANSPARENT_RED_VALUE:     *value = configuration->mTransparentRedValue;    break;
325       case EGL_BIND_TO_TEXTURE_RGB:       *value = configuration->mBindToTextureRGB;       break;
326       case EGL_BIND_TO_TEXTURE_RGBA:      *value = configuration->mBindToTextureRGBA;      break;
327       case EGL_MIN_SWAP_INTERVAL:         *value = configuration->mMinSwapInterval;        break;
328       case EGL_MAX_SWAP_INTERVAL:         *value = configuration->mMaxSwapInterval;        break;
329       case EGL_LUMINANCE_SIZE:            *value = configuration->mLuminanceSize;          break;
330       case EGL_ALPHA_MASK_SIZE:           *value = configuration->mAlphaMaskSize;          break;
331       case EGL_COLOR_BUFFER_TYPE:         *value = configuration->mColorBufferType;        break;
332       case EGL_RENDERABLE_TYPE:           *value = configuration->mRenderableType;         break;
333       case EGL_MATCH_NATIVE_PIXMAP:       *value = false; UNIMPLEMENTED();                 break;
334       case EGL_CONFORMANT:                *value = configuration->mConformant;             break;
335       default:
336         return false;
337     }
338 
339     return true;
340 }
341 
createDevice()342 bool Display::createDevice()
343 {
344     D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
345     DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
346 
347     HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
348 
349     if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
350     {
351         return error(EGL_BAD_ALLOC, false);
352     }
353 
354     if (FAILED(result))
355     {
356         result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
357 
358         if (FAILED(result))
359         {
360             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
361             return error(EGL_BAD_ALLOC, false);
362         }
363     }
364 
365     // Permanent non-default states
366     mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
367 
368     mSceneStarted = false;
369 
370     return true;
371 }
372 
resetDevice()373 bool Display::resetDevice()
374 {
375     D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
376     HRESULT result;
377 
378     do
379     {
380         Sleep(0);   // Give the graphics driver some CPU time
381 
382         result = mDevice->Reset(&presentParameters);
383     }
384     while (result == D3DERR_DEVICELOST);
385 
386     if (FAILED(result))
387     {
388         return error(EGL_BAD_ALLOC, false);
389     }
390 
391     ASSERT(SUCCEEDED(result));
392 
393     return true;
394 }
395 
createWindowSurface(HWND window,EGLConfig config)396 Surface *Display::createWindowSurface(HWND window, EGLConfig config)
397 {
398     const Config *configuration = mConfigSet.get(config);
399 
400     Surface *surface = new Surface(this, configuration, window);
401     mSurfaceSet.insert(surface);
402 
403     return surface;
404 }
405 
createContext(EGLConfig configHandle,const gl::Context * shareContext)406 EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext)
407 {
408     if (!mDevice)
409     {
410         if (!createDevice())
411         {
412             return NULL;
413         }
414     }
415     else if (FAILED(mDevice->TestCooperativeLevel()))   // Lost device
416     {
417         if (!resetDevice())
418         {
419             return NULL;
420         }
421 
422         // Restore any surfaces that may have been lost
423         for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
424         {
425             (*surface)->resetSwapChain();
426         }
427     }
428 
429     const egl::Config *config = mConfigSet.get(configHandle);
430 
431     gl::Context *context = glCreateContext(config, shareContext);
432     mContextSet.insert(context);
433 
434     return context;
435 }
436 
destroySurface(egl::Surface * surface)437 void Display::destroySurface(egl::Surface *surface)
438 {
439     delete surface;
440     mSurfaceSet.erase(surface);
441 }
442 
destroyContext(gl::Context * context)443 void Display::destroyContext(gl::Context *context)
444 {
445     glDestroyContext(context);
446     mContextSet.erase(context);
447 
448     if (mContextSet.empty() && mDevice && FAILED(mDevice->TestCooperativeLevel()))   // Last context of a lost device
449     {
450         for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
451         {
452             (*surface)->release();
453         }
454     }
455 }
456 
isInitialized()457 bool Display::isInitialized()
458 {
459     return mD3d9 != NULL && mConfigSet.size() > 0;
460 }
461 
isValidConfig(EGLConfig config)462 bool Display::isValidConfig(EGLConfig config)
463 {
464     return mConfigSet.get(config) != NULL;
465 }
466 
isValidContext(gl::Context * context)467 bool Display::isValidContext(gl::Context *context)
468 {
469     return mContextSet.find(context) != mContextSet.end();
470 }
471 
isValidSurface(egl::Surface * surface)472 bool Display::isValidSurface(egl::Surface *surface)
473 {
474     return mSurfaceSet.find(surface) != mSurfaceSet.end();
475 }
476 
hasExistingWindowSurface(HWND window)477 bool Display::hasExistingWindowSurface(HWND window)
478 {
479     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
480     {
481         if ((*surface)->getWindowHandle() == window)
482         {
483             return true;
484         }
485     }
486 
487     return false;
488 }
489 
getMinSwapInterval()490 EGLint Display::getMinSwapInterval()
491 {
492     return mMinSwapInterval;
493 }
494 
getMaxSwapInterval()495 EGLint Display::getMaxSwapInterval()
496 {
497     return mMaxSwapInterval;
498 }
499 
getDevice()500 IDirect3DDevice9 *Display::getDevice()
501 {
502     if (!mDevice)
503     {
504         if (!createDevice())
505         {
506             return NULL;
507         }
508     }
509 
510     return mDevice;
511 }
512 
getDeviceCaps()513 D3DCAPS9 Display::getDeviceCaps()
514 {
515     return mDeviceCaps;
516 }
517 
getMultiSampleSupport(D3DFORMAT format,bool * multiSampleArray)518 void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
519 {
520     for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
521     {
522         HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
523                                                            TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
524 
525         multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
526     }
527 }
528 
getCompressedTextureSupport()529 bool Display::getCompressedTextureSupport()
530 {
531     D3DDISPLAYMODE currentDisplayMode;
532     mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
533 
534     return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
535 }
536 
getFloatTextureSupport(bool * filtering,bool * renderable)537 bool Display::getFloatTextureSupport(bool *filtering, bool *renderable)
538 {
539     D3DDISPLAYMODE currentDisplayMode;
540     mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
541 
542     *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
543                                                     D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
544                  SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
545                                                     D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
546 
547     *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
548                                                      D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
549                   SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
550                                                      D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
551 
552     if (!filtering && !renderable)
553     {
554         return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
555                                                   D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
556                SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
557                                                   D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
558     }
559     else
560     {
561         return true;
562     }
563 }
564 
getHalfFloatTextureSupport(bool * filtering,bool * renderable)565 bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable)
566 {
567     D3DDISPLAYMODE currentDisplayMode;
568     mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
569 
570     *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
571                                                     D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
572                  SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
573                                                     D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
574 
575     *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
576                                                     D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
577                  SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
578                                                     D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
579 
580     if (!filtering && !renderable)
581     {
582         return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
583                                                   D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
584                SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
585                                                   D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
586     }
587     else
588     {
589         return true;
590     }
591 }
592 
getLuminanceTextureSupport()593 bool Display::getLuminanceTextureSupport()
594 {
595     D3DDISPLAYMODE currentDisplayMode;
596     mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
597 
598     return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
599 }
600 
getLuminanceAlphaTextureSupport()601 bool Display::getLuminanceAlphaTextureSupport()
602 {
603     D3DDISPLAYMODE currentDisplayMode;
604     mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
605 
606     return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
607 }
608 
getBufferPool(DWORD usage) const609 D3DPOOL Display::getBufferPool(DWORD usage) const
610 {
611     if (mD3d9ex != NULL)
612     {
613         return D3DPOOL_DEFAULT;
614     }
615     else
616     {
617         if (!(usage & D3DUSAGE_DYNAMIC))
618         {
619             return D3DPOOL_MANAGED;
620         }
621     }
622 
623     return D3DPOOL_DEFAULT;
624 }
625 
getEventQuerySupport()626 bool Display::getEventQuerySupport()
627 {
628     IDirect3DQuery9 *query;
629     HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
630     if (SUCCEEDED(result))
631     {
632         query->Release();
633     }
634 
635     return result != D3DERR_NOTAVAILABLE;
636 }
637 
getDefaultPresentParameters()638 D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
639 {
640     D3DPRESENT_PARAMETERS presentParameters = {0};
641 
642     // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
643     presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
644     presentParameters.BackBufferCount = 1;
645     presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
646     presentParameters.BackBufferWidth = 1;
647     presentParameters.BackBufferHeight = 1;
648     presentParameters.EnableAutoDepthStencil = FALSE;
649     presentParameters.Flags = 0;
650     presentParameters.hDeviceWindow = mDeviceWindow;
651     presentParameters.MultiSampleQuality = 0;
652     presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
653     presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
654     presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
655     presentParameters.Windowed = TRUE;
656 
657     return presentParameters;
658 }
659 }