blob: a6b75d744242b043981feebd6ed4444e307d0928 [file] [log] [blame]
daniel@transgaming.com621ce052012-10-31 17:52:29 +00001//
2// Copyright (c) 2012 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// Renderer.cpp: Implements a back-end specific class that hides the details of the
8// implementation-specific renderer.
9
10#include "libGLESv2/renderer/Renderer.h"
11#include "common/debug.h"
12#include "libGLESv2/utilities.h"
13
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000014#include "libEGL/Display.h"
15
daniel@transgaming.com621ce052012-10-31 17:52:29 +000016// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
17#define REF_RAST 0
18
19// The "Debug This Pixel..." feature in PIX often fails when using the
20// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7
21// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file.
22#if !defined(ANGLE_ENABLE_D3D9EX)
23// Enables use of the IDirect3D9Ex interface, when available
24#define ANGLE_ENABLE_D3D9EX 1
25#endif // !defined(ANGLE_ENABLE_D3D9EX)
26
27namespace renderer
28{
29
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000030Renderer::Renderer(egl::Display *display, HMODULE hModule, HDC hDc): mDc(hDc)
daniel@transgaming.com621ce052012-10-31 17:52:29 +000031{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000032 mDisplay = display;
daniel@transgaming.com621ce052012-10-31 17:52:29 +000033 mD3d9Module = hModule;
34
35 mD3d9 = NULL;
36 mD3d9Ex = NULL;
37 mDevice = NULL;
38 mDeviceEx = NULL;
39 mDeviceWindow = NULL;
40
41 mAdapter = D3DADAPTER_DEFAULT;
42
43 #if REF_RAST == 1 || defined(FORCE_REF_RAST)
44 mDeviceType = D3DDEVTYPE_REF;
45 #else
46 mDeviceType = D3DDEVTYPE_HAL;
47 #endif
48
49 mDeviceLost = false;
50}
51
52Renderer::~Renderer()
53{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000054 releaseDeviceResources();
55
daniel@transgaming.com621ce052012-10-31 17:52:29 +000056 if (mDevice)
57 {
58 // If the device is lost, reset it first to prevent leaving the driver in an unstable state
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +000059 if (testDeviceLost(false))
daniel@transgaming.com621ce052012-10-31 17:52:29 +000060 {
61 resetDevice();
62 }
63
64 mDevice->Release();
65 mDevice = NULL;
66 }
67
68 if (mDeviceEx)
69 {
70 mDeviceEx->Release();
71 mDeviceEx = NULL;
72 }
73
74 if (mD3d9)
75 {
76 mD3d9->Release();
77 mD3d9 = NULL;
78 }
79
80 if (mDeviceWindow)
81 {
82 DestroyWindow(mDeviceWindow);
83 mDeviceWindow = NULL;
84 }
85
86 if (mD3d9Ex)
87 {
88 mD3d9Ex->Release();
89 mD3d9Ex = NULL;
90 }
91
92 if (mD3d9Module)
93 {
94 mD3d9Module = NULL;
95 }
96
97}
98
99EGLint Renderer::initialize()
100{
101 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
102 Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
103
104 // Use Direct3D9Ex if available. Among other things, this version is less
105 // inclined to report a lost context, for example when the user switches
106 // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
107 if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
108 {
109 ASSERT(mD3d9Ex);
110 mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
111 ASSERT(mD3d9);
112 }
113 else
114 {
115 mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
116 }
117
118 if (!mD3d9)
119 {
120 ERR("Could not create D3D9 device - aborting!\n");
121 return EGL_NOT_INITIALIZED;
122 }
123 if (mDc != NULL)
124 {
125 // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
126 }
127
128 HRESULT result;
129
130 // Give up on getting device caps after about one second.
131 for (int i = 0; i < 10; ++i)
132 {
133 result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
134 if (SUCCEEDED(result))
135 {
136 break;
137 }
138 else if (result == D3DERR_NOTAVAILABLE)
139 {
140 Sleep(100); // Give the driver some time to initialize/recover
141 }
142 else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
143 {
144 ERR("failed to get device caps (0x%x)\n", result);
145 return EGL_NOT_INITIALIZED;
146 }
147 }
148
149 if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
150 {
151 ERR("Renderer does not support PS 2.0. aborting!\n");
152 return EGL_NOT_INITIALIZED;
153 }
154
155 // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
156 // This is required by Texture2D::convertToRenderTarget.
157 if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
158 {
159 ERR("Renderer does not support stretctrect from textures!\n");
160 return EGL_NOT_INITIALIZED;
161 }
162
163 mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
164
165 // ATI cards on XP have problems with non-power-of-two textures.
166 mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
167 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
168 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
169 !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD);
170
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000171 // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec
172 mSupportsTextureFilterAnisotropy = ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2));
173
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000174 static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
175 static const TCHAR className[] = TEXT("STATIC");
176
177 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
178
179 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
180 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
181
182 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
183 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
184 {
185 return EGL_BAD_ALLOC;
186 }
187
188 if (FAILED(result))
189 {
190 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
191
192 if (FAILED(result))
193 {
194 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
195 return EGL_BAD_ALLOC;
196 }
197 }
198
199 if (mD3d9Ex)
200 {
201 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
202 ASSERT(SUCCEEDED(result));
203 }
204
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000205 mVertexShaderCache.initialize(mDevice);
206 mPixelShaderCache.initialize(mDevice);
207
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000208 initializeDevice();
209
210 return EGL_SUCCESS;
211}
212
213// do any one-time device initialization
214// NOTE: this is also needed after a device lost/reset
215// to reset the scene status and ensure the default states are reset.
216void Renderer::initializeDevice()
217{
218 // Permanent non-default states
219 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
220 mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE);
221
222 if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
223 {
224 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize);
225 }
226 else
227 {
228 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f
229 }
230
231 mSceneStarted = false;
232}
233
234D3DPRESENT_PARAMETERS Renderer::getDefaultPresentParameters()
235{
236 D3DPRESENT_PARAMETERS presentParameters = {0};
237
238 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
239 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
240 presentParameters.BackBufferCount = 1;
241 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
242 presentParameters.BackBufferWidth = 1;
243 presentParameters.BackBufferHeight = 1;
244 presentParameters.EnableAutoDepthStencil = FALSE;
245 presentParameters.Flags = 0;
246 presentParameters.hDeviceWindow = mDeviceWindow;
247 presentParameters.MultiSampleQuality = 0;
248 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
249 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
250 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
251 presentParameters.Windowed = TRUE;
252
253 return presentParameters;
254}
255
256void Renderer::startScene()
257{
258 if (!mSceneStarted)
259 {
260 long result = mDevice->BeginScene();
261 if (SUCCEEDED(result)) {
262 // This is defensive checking against the device being
263 // lost at unexpected times.
264 mSceneStarted = true;
265 }
266 }
267}
268
269void Renderer::endScene()
270{
271 if (mSceneStarted)
272 {
273 // EndScene can fail if the device was lost, for example due
274 // to a TDR during a draw call.
275 mDevice->EndScene();
276 mSceneStarted = false;
277 }
278}
279
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000280// D3D9_REPLACE
281void Renderer::sync(bool block)
282{
283 HRESULT result;
284
285 IDirect3DQuery9* query = allocateEventQuery();
286 if (!query)
287 {
288 return;
289 }
290
291 result = query->Issue(D3DISSUE_END);
292 ASSERT(SUCCEEDED(result));
293
294 do
295 {
296 result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
297
298 if(block && result == S_FALSE)
299 {
300 // Keep polling, but allow other threads to do something useful first
301 Sleep(0);
302 // explicitly check for device loss
303 // some drivers seem to return S_FALSE even if the device is lost
304 // instead of D3DERR_DEVICELOST like they should
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000305 if (testDeviceLost(false))
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000306 {
307 result = D3DERR_DEVICELOST;
308 }
309 }
310 }
311 while(block && result == S_FALSE);
312
313 freeEventQuery(query);
314
315 if (isDeviceLostError(result))
316 {
317 mDisplay->notifyDeviceLost();
318 }
319}
320
321// D3D9_REPLACE
322IDirect3DQuery9* Renderer::allocateEventQuery()
323{
324 IDirect3DQuery9 *query = NULL;
325
326 if (mEventQueryPool.empty())
327 {
328 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
329 ASSERT(SUCCEEDED(result));
330 }
331 else
332 {
333 query = mEventQueryPool.back();
334 mEventQueryPool.pop_back();
335 }
336
337 return query;
338}
339
340// D3D9_REPLACE
341void Renderer::freeEventQuery(IDirect3DQuery9* query)
342{
343 if (mEventQueryPool.size() > 1000)
344 {
345 query->Release();
346 }
347 else
348 {
349 mEventQueryPool.push_back(query);
350 }
351}
352
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000353IDirect3DVertexShader9 *Renderer::createVertexShader(const DWORD *function, size_t length)
354{
355 return mVertexShaderCache.create(function, length);
356}
357
358IDirect3DPixelShader9 *Renderer::createPixelShader(const DWORD *function, size_t length)
359{
360 return mPixelShaderCache.create(function, length);
361}
362
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000363
364void Renderer::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState)
365{
366 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
367 int d3dSampler = index + d3dSamplerOffset;
368
369 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(samplerState.wrapS));
370 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(samplerState.wrapT));
371
372 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy));
373 D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
374 es2dx::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy);
375 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
376 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
377 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.lodOffset);
378 if (mSupportsTextureFilterAnisotropy)
379 {
380 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy);
381 }
382}
383
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000384void Renderer::releaseDeviceResources()
385{
386 while (!mEventQueryPool.empty())
387 {
388 mEventQueryPool.back()->Release();
389 mEventQueryPool.pop_back();
390 }
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000391
392 mVertexShaderCache.clear();
393 mPixelShaderCache.clear();
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000394}
395
396
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000397void Renderer::markDeviceLost()
398{
399 mDeviceLost = true;
400}
401
402bool Renderer::isDeviceLost()
403{
404 return mDeviceLost;
405}
406
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000407// set notify to true to broadcast a message to all contexts of the device loss
408bool Renderer::testDeviceLost(bool notify)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000409{
410 bool isLost = false;
411
412 if (mDeviceEx)
413 {
414 isLost = FAILED(mDeviceEx->CheckDeviceState(NULL));
415 }
416 else if (mDevice)
417 {
418 isLost = FAILED(mDevice->TestCooperativeLevel());
419 }
420 else
421 {
422 // No device yet, so no reset required
423 }
424
425 if (isLost)
426 {
427 // ensure we note the device loss --
428 // we'll probably get this done again by markDeviceLost
429 // but best to remember it!
430 // Note that we don't want to clear the device loss status here
431 // -- this needs to be done by resetDevice
432 mDeviceLost = true;
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000433 if (notify)
434 {
435 mDisplay->notifyDeviceLost();
436 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000437 }
438
439 return isLost;
440}
441
442bool Renderer::testDeviceResettable()
443{
444 HRESULT status = D3D_OK;
445
446 if (mDeviceEx)
447 {
448 status = mDeviceEx->CheckDeviceState(NULL);
449 }
450 else if (mDevice)
451 {
452 status = mDevice->TestCooperativeLevel();
453 }
454
455 switch (status)
456 {
457 case D3DERR_DEVICENOTRESET:
458 case D3DERR_DEVICEHUNG:
459 return true;
460 default:
461 return false;
462 }
463}
464
465bool Renderer::resetDevice()
466{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000467 releaseDeviceResources();
468
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000469 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
470
471 HRESULT result = D3D_OK;
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000472 bool lost = testDeviceLost(false);
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000473 int attempts = 3;
474
475 while (lost && attempts > 0)
476 {
477 if (mDeviceEx)
478 {
479 Sleep(500); // Give the graphics driver some CPU time
480 result = mDeviceEx->ResetEx(&presentParameters, NULL);
481 }
482 else
483 {
484 result = mDevice->TestCooperativeLevel();
485 while (result == D3DERR_DEVICELOST)
486 {
487 Sleep(100); // Give the graphics driver some CPU time
488 result = mDevice->TestCooperativeLevel();
489 }
490
491 if (result == D3DERR_DEVICENOTRESET)
492 {
493 result = mDevice->Reset(&presentParameters);
494 }
495 }
496
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000497 lost = testDeviceLost(false);
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000498 attempts --;
499 }
500
501 if (FAILED(result))
502 {
503 ERR("Reset/ResetEx failed multiple times: 0x%08X", result);
504 return false;
505 }
506
507 // reset device defaults
508 initializeDevice();
509 mDeviceLost = false;
510
511 return true;
512}
513
514void Renderer::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
515{
516 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
517 {
518 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
519 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
520
521 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
522 }
523}
524
525bool Renderer::getDXT1TextureSupport()
526{
527 D3DDISPLAYMODE currentDisplayMode;
528 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
529
530 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
531}
532
533bool Renderer::getDXT3TextureSupport()
534{
535 D3DDISPLAYMODE currentDisplayMode;
536 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
537
538 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3));
539}
540
541bool Renderer::getDXT5TextureSupport()
542{
543 D3DDISPLAYMODE currentDisplayMode;
544 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
545
546 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5));
547}
548
549// we use INTZ for depth textures in Direct3D9
550// we also want NULL texture support to ensure the we can make depth-only FBOs
551// see http://aras-p.info/texts/D3D9GPUHacks.html
552bool Renderer::getDepthTextureSupport() const
553{
554 D3DDISPLAYMODE currentDisplayMode;
555 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
556
557 bool intz = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
558 D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ));
559 bool null = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
560 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL));
561
562 return intz && null;
563}
564
565bool Renderer::getFloat32TextureSupport(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_A32B32G32R32F)) &&
572 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
573 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
574
575 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
576 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
577 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
578 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
579
580 if (!*filtering && !*renderable)
581 {
582 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
583 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
584 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
585 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
586 }
587 else
588 {
589 return true;
590 }
591}
592
593bool Renderer::getFloat16TextureSupport(bool *filtering, bool *renderable)
594{
595 D3DDISPLAYMODE currentDisplayMode;
596 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
597
598 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
599 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
600 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
601 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
602
603 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
604 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
605 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
606 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
607
608 if (!*filtering && !*renderable)
609 {
610 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
611 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
612 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
613 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
614 }
615 else
616 {
617 return true;
618 }
619}
620
621bool Renderer::getLuminanceTextureSupport()
622{
623 D3DDISPLAYMODE currentDisplayMode;
624 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
625
626 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
627}
628
629bool Renderer::getLuminanceAlphaTextureSupport()
630{
631 D3DDISPLAYMODE currentDisplayMode;
632 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
633
634 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
635}
636
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000637bool Renderer::getTextureFilterAnisotropySupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000638{
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000639 return mSupportsTextureFilterAnisotropy;
640}
641
642float Renderer::getTextureMaxAnisotropy() const
643{
644 if (mSupportsTextureFilterAnisotropy)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000645 {
646 return mDeviceCaps.MaxAnisotropy;
647 }
648 return 1.0f;
649}
650
651bool Renderer::getEventQuerySupport()
652{
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000653 IDirect3DQuery9 *query = allocateEventQuery();
654 if (query)
655 {
656 freeEventQuery(query);
657 return true;
658 }
659 else
660 {
661 return false;
662 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000663 return true;
664}
665
666// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
667// We test this using D3D9 by checking support for the R16F format.
668bool Renderer::getVertexTextureSupport() const
669{
670 if (!mDevice || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
671 {
672 return false;
673 }
674
675 D3DDISPLAYMODE currentDisplayMode;
676 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
677
678 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
679
680 return SUCCEEDED(result);
681}
682
683bool Renderer::getNonPower2TextureSupport() const
684{
685 return mSupportsNonPower2Textures;
686}
687
688bool Renderer::getOcclusionQuerySupport() const
689{
690 if (!mDevice)
691 {
692 return false;
693 }
694
695 IDirect3DQuery9 *query = NULL;
696 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query);
697 if (SUCCEEDED(result) && query)
698 {
699 query->Release();
700 return true;
701 }
702 else
703 {
704 return false;
705 }
706}
707
708bool Renderer::getInstancingSupport() const
709{
710 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
711}
712
daniel@transgaming.com313e3922012-10-31 17:52:39 +0000713bool Renderer::getShareHandleSupport() const
714{
715 // PIX doesn't seem to support using share handles, so disable them.
716 // D3D9_REPLACE
717 return isD3d9ExDevice() && !gl::perfActive();
718}
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000719
720D3DPOOL Renderer::getBufferPool(DWORD usage) const
721{
722 if (mD3d9Ex != NULL)
723 {
724 return D3DPOOL_DEFAULT;
725 }
726 else
727 {
728 if (!(usage & D3DUSAGE_DYNAMIC))
729 {
730 return D3DPOOL_MANAGED;
731 }
732 }
733
734 return D3DPOOL_DEFAULT;
735}
736
737D3DPOOL Renderer::getTexturePool(DWORD usage) const
738{
739 if (mD3d9Ex != NULL)
740 {
741 return D3DPOOL_DEFAULT;
742 }
743 else
744 {
745 if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)))
746 {
747 return D3DPOOL_MANAGED;
748 }
749 }
750
751 return D3DPOOL_DEFAULT;
752}
753
754}