blob: d685527f453f822a91471961c81dd603e82cc00e [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.com5f4c1362012-10-31 18:29:00 +0000174 mMinSwapInterval = 4;
175 mMaxSwapInterval = 0;
176
177 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)
178 {
179 mMinSwapInterval = std::min(mMinSwapInterval, 0);
180 mMaxSwapInterval = std::max(mMaxSwapInterval, 0);
181 }
182 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)
183 {
184 mMinSwapInterval = std::min(mMinSwapInterval, 1);
185 mMaxSwapInterval = std::max(mMaxSwapInterval, 1);
186 }
187 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)
188 {
189 mMinSwapInterval = std::min(mMinSwapInterval, 2);
190 mMaxSwapInterval = std::max(mMaxSwapInterval, 2);
191 }
192 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE)
193 {
194 mMinSwapInterval = std::min(mMinSwapInterval, 3);
195 mMaxSwapInterval = std::max(mMaxSwapInterval, 3);
196 }
197 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR)
198 {
199 mMinSwapInterval = std::min(mMinSwapInterval, 4);
200 mMaxSwapInterval = std::max(mMaxSwapInterval, 4);
201 }
202
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000203 static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
204 static const TCHAR className[] = TEXT("STATIC");
205
206 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
207
208 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
209 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
210
211 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
212 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
213 {
214 return EGL_BAD_ALLOC;
215 }
216
217 if (FAILED(result))
218 {
219 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
220
221 if (FAILED(result))
222 {
223 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
224 return EGL_BAD_ALLOC;
225 }
226 }
227
228 if (mD3d9Ex)
229 {
230 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
231 ASSERT(SUCCEEDED(result));
232 }
233
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000234 mVertexShaderCache.initialize(mDevice);
235 mPixelShaderCache.initialize(mDevice);
236
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000237 initializeDevice();
238
239 return EGL_SUCCESS;
240}
241
242// do any one-time device initialization
243// NOTE: this is also needed after a device lost/reset
244// to reset the scene status and ensure the default states are reset.
245void Renderer::initializeDevice()
246{
247 // Permanent non-default states
248 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
249 mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE);
250
251 if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
252 {
253 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize);
254 }
255 else
256 {
257 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f
258 }
259
260 mSceneStarted = false;
261}
262
263D3DPRESENT_PARAMETERS Renderer::getDefaultPresentParameters()
264{
265 D3DPRESENT_PARAMETERS presentParameters = {0};
266
267 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
268 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
269 presentParameters.BackBufferCount = 1;
270 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
271 presentParameters.BackBufferWidth = 1;
272 presentParameters.BackBufferHeight = 1;
273 presentParameters.EnableAutoDepthStencil = FALSE;
274 presentParameters.Flags = 0;
275 presentParameters.hDeviceWindow = mDeviceWindow;
276 presentParameters.MultiSampleQuality = 0;
277 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
278 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
279 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
280 presentParameters.Windowed = TRUE;
281
282 return presentParameters;
283}
284
285void Renderer::startScene()
286{
287 if (!mSceneStarted)
288 {
289 long result = mDevice->BeginScene();
290 if (SUCCEEDED(result)) {
291 // This is defensive checking against the device being
292 // lost at unexpected times.
293 mSceneStarted = true;
294 }
295 }
296}
297
298void Renderer::endScene()
299{
300 if (mSceneStarted)
301 {
302 // EndScene can fail if the device was lost, for example due
303 // to a TDR during a draw call.
304 mDevice->EndScene();
305 mSceneStarted = false;
306 }
307}
308
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000309// D3D9_REPLACE
310void Renderer::sync(bool block)
311{
312 HRESULT result;
313
314 IDirect3DQuery9* query = allocateEventQuery();
315 if (!query)
316 {
317 return;
318 }
319
320 result = query->Issue(D3DISSUE_END);
321 ASSERT(SUCCEEDED(result));
322
323 do
324 {
325 result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
326
327 if(block && result == S_FALSE)
328 {
329 // Keep polling, but allow other threads to do something useful first
330 Sleep(0);
331 // explicitly check for device loss
332 // some drivers seem to return S_FALSE even if the device is lost
333 // instead of D3DERR_DEVICELOST like they should
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000334 if (testDeviceLost(false))
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000335 {
336 result = D3DERR_DEVICELOST;
337 }
338 }
339 }
340 while(block && result == S_FALSE);
341
342 freeEventQuery(query);
343
344 if (isDeviceLostError(result))
345 {
346 mDisplay->notifyDeviceLost();
347 }
348}
349
350// D3D9_REPLACE
351IDirect3DQuery9* Renderer::allocateEventQuery()
352{
353 IDirect3DQuery9 *query = NULL;
354
355 if (mEventQueryPool.empty())
356 {
357 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
358 ASSERT(SUCCEEDED(result));
359 }
360 else
361 {
362 query = mEventQueryPool.back();
363 mEventQueryPool.pop_back();
364 }
365
366 return query;
367}
368
369// D3D9_REPLACE
370void Renderer::freeEventQuery(IDirect3DQuery9* query)
371{
372 if (mEventQueryPool.size() > 1000)
373 {
374 query->Release();
375 }
376 else
377 {
378 mEventQueryPool.push_back(query);
379 }
380}
381
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000382IDirect3DVertexShader9 *Renderer::createVertexShader(const DWORD *function, size_t length)
383{
384 return mVertexShaderCache.create(function, length);
385}
386
387IDirect3DPixelShader9 *Renderer::createPixelShader(const DWORD *function, size_t length)
388{
389 return mPixelShaderCache.create(function, length);
390}
391
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000392
393void Renderer::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState)
394{
395 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
396 int d3dSampler = index + d3dSamplerOffset;
397
398 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(samplerState.wrapS));
399 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(samplerState.wrapT));
400
401 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy));
402 D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
403 es2dx::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy);
404 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
405 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
406 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.lodOffset);
407 if (mSupportsTextureFilterAnisotropy)
408 {
409 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy);
410 }
411}
412
daniel@transgaming.coma734f272012-10-31 18:07:48 +0000413void Renderer::setTexture(gl::SamplerType type, int index, gl::Texture *texture)
414{
415 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
416 int d3dSampler = index + d3dSamplerOffset;
417 IDirect3DBaseTexture9 *d3dTexture = NULL;
418
419 if (texture)
420 {
421 d3dTexture = texture->getD3DTexture();
422 // If we get NULL back from getTexture here, something went wrong
423 // in the texture class and we're unexpectedly missing the d3d texture
424 ASSERT(d3dTexture != NULL);
425 }
426
427 mDevice->SetTexture(d3dSampler, d3dTexture);
428}
429
430
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000431void Renderer::releaseDeviceResources()
432{
433 while (!mEventQueryPool.empty())
434 {
435 mEventQueryPool.back()->Release();
436 mEventQueryPool.pop_back();
437 }
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000438
439 mVertexShaderCache.clear();
440 mPixelShaderCache.clear();
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000441}
442
443
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000444void Renderer::markDeviceLost()
445{
446 mDeviceLost = true;
447}
448
449bool Renderer::isDeviceLost()
450{
451 return mDeviceLost;
452}
453
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000454// set notify to true to broadcast a message to all contexts of the device loss
455bool Renderer::testDeviceLost(bool notify)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000456{
457 bool isLost = false;
458
459 if (mDeviceEx)
460 {
461 isLost = FAILED(mDeviceEx->CheckDeviceState(NULL));
462 }
463 else if (mDevice)
464 {
465 isLost = FAILED(mDevice->TestCooperativeLevel());
466 }
467 else
468 {
469 // No device yet, so no reset required
470 }
471
472 if (isLost)
473 {
474 // ensure we note the device loss --
475 // we'll probably get this done again by markDeviceLost
476 // but best to remember it!
477 // Note that we don't want to clear the device loss status here
478 // -- this needs to be done by resetDevice
479 mDeviceLost = true;
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000480 if (notify)
481 {
482 mDisplay->notifyDeviceLost();
483 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000484 }
485
486 return isLost;
487}
488
489bool Renderer::testDeviceResettable()
490{
491 HRESULT status = D3D_OK;
492
493 if (mDeviceEx)
494 {
495 status = mDeviceEx->CheckDeviceState(NULL);
496 }
497 else if (mDevice)
498 {
499 status = mDevice->TestCooperativeLevel();
500 }
501
502 switch (status)
503 {
504 case D3DERR_DEVICENOTRESET:
505 case D3DERR_DEVICEHUNG:
506 return true;
507 default:
508 return false;
509 }
510}
511
512bool Renderer::resetDevice()
513{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000514 releaseDeviceResources();
515
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000516 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
517
518 HRESULT result = D3D_OK;
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000519 bool lost = testDeviceLost(false);
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000520 int attempts = 3;
521
522 while (lost && attempts > 0)
523 {
524 if (mDeviceEx)
525 {
526 Sleep(500); // Give the graphics driver some CPU time
527 result = mDeviceEx->ResetEx(&presentParameters, NULL);
528 }
529 else
530 {
531 result = mDevice->TestCooperativeLevel();
532 while (result == D3DERR_DEVICELOST)
533 {
534 Sleep(100); // Give the graphics driver some CPU time
535 result = mDevice->TestCooperativeLevel();
536 }
537
538 if (result == D3DERR_DEVICENOTRESET)
539 {
540 result = mDevice->Reset(&presentParameters);
541 }
542 }
543
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000544 lost = testDeviceLost(false);
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000545 attempts --;
546 }
547
548 if (FAILED(result))
549 {
550 ERR("Reset/ResetEx failed multiple times: 0x%08X", result);
551 return false;
552 }
553
554 // reset device defaults
555 initializeDevice();
556 mDeviceLost = false;
557
558 return true;
559}
560
561void Renderer::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
562{
563 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
564 {
565 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
566 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
567
568 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
569 }
570}
571
572bool Renderer::getDXT1TextureSupport()
573{
574 D3DDISPLAYMODE currentDisplayMode;
575 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
576
577 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
578}
579
580bool Renderer::getDXT3TextureSupport()
581{
582 D3DDISPLAYMODE currentDisplayMode;
583 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
584
585 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3));
586}
587
588bool Renderer::getDXT5TextureSupport()
589{
590 D3DDISPLAYMODE currentDisplayMode;
591 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
592
593 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5));
594}
595
596// we use INTZ for depth textures in Direct3D9
597// we also want NULL texture support to ensure the we can make depth-only FBOs
598// see http://aras-p.info/texts/D3D9GPUHacks.html
599bool Renderer::getDepthTextureSupport() const
600{
601 D3DDISPLAYMODE currentDisplayMode;
602 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
603
604 bool intz = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
605 D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ));
606 bool null = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
607 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL));
608
609 return intz && null;
610}
611
612bool Renderer::getFloat32TextureSupport(bool *filtering, bool *renderable)
613{
614 D3DDISPLAYMODE currentDisplayMode;
615 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
616
617 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
618 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
619 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
620 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
621
622 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
623 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
624 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
625 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
626
627 if (!*filtering && !*renderable)
628 {
629 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
630 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
631 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
632 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
633 }
634 else
635 {
636 return true;
637 }
638}
639
640bool Renderer::getFloat16TextureSupport(bool *filtering, bool *renderable)
641{
642 D3DDISPLAYMODE currentDisplayMode;
643 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
644
645 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
646 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
647 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
648 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
649
650 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
651 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
652 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
653 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
654
655 if (!*filtering && !*renderable)
656 {
657 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
658 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
659 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
660 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
661 }
662 else
663 {
664 return true;
665 }
666}
667
668bool Renderer::getLuminanceTextureSupport()
669{
670 D3DDISPLAYMODE currentDisplayMode;
671 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
672
673 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
674}
675
676bool Renderer::getLuminanceAlphaTextureSupport()
677{
678 D3DDISPLAYMODE currentDisplayMode;
679 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
680
681 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
682}
683
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000684bool Renderer::getTextureFilterAnisotropySupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000685{
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000686 return mSupportsTextureFilterAnisotropy;
687}
688
689float Renderer::getTextureMaxAnisotropy() const
690{
691 if (mSupportsTextureFilterAnisotropy)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000692 {
693 return mDeviceCaps.MaxAnisotropy;
694 }
695 return 1.0f;
696}
697
698bool Renderer::getEventQuerySupport()
699{
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000700 IDirect3DQuery9 *query = allocateEventQuery();
701 if (query)
702 {
703 freeEventQuery(query);
704 return true;
705 }
706 else
707 {
708 return false;
709 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000710 return true;
711}
712
713// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
714// We test this using D3D9 by checking support for the R16F format.
715bool Renderer::getVertexTextureSupport() const
716{
717 if (!mDevice || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
718 {
719 return false;
720 }
721
722 D3DDISPLAYMODE currentDisplayMode;
723 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
724
725 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
726
727 return SUCCEEDED(result);
728}
729
730bool Renderer::getNonPower2TextureSupport() const
731{
732 return mSupportsNonPower2Textures;
733}
734
735bool Renderer::getOcclusionQuerySupport() const
736{
737 if (!mDevice)
738 {
739 return false;
740 }
741
742 IDirect3DQuery9 *query = NULL;
743 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query);
744 if (SUCCEEDED(result) && query)
745 {
746 query->Release();
747 return true;
748 }
749 else
750 {
751 return false;
752 }
753}
754
755bool Renderer::getInstancingSupport() const
756{
757 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
758}
759
daniel@transgaming.com313e3922012-10-31 17:52:39 +0000760bool Renderer::getShareHandleSupport() const
761{
762 // PIX doesn't seem to support using share handles, so disable them.
763 // D3D9_REPLACE
764 return isD3d9ExDevice() && !gl::perfActive();
765}
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000766
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000767bool Renderer::getShaderModel3Support() const
768{
769 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
770}
771
772float Renderer::getMaxPointSize() const
773{
774 return mDeviceCaps.MaxPointSize;
775}
776
777int Renderer::getMaxTextureWidth() const
778{
779 return (int)mDeviceCaps.MaxTextureWidth;
780}
781
782int Renderer::getMaxTextureHeight() const
783{
784 return (int)mDeviceCaps.MaxTextureHeight;
785}
786
787bool Renderer::get32BitIndexSupport() const
788{
789 return mDeviceCaps.MaxVertexIndex >= (1 << 16);
790}
791
792DWORD Renderer::getCapsDeclTypes() const
793{
794 return mDeviceCaps.DeclTypes;
795}
796
797int Renderer::getMinSwapInterval() const
798{
799 return mMinSwapInterval;
800}
801
802int Renderer::getMaxSwapInterval() const
803{
804 return mMaxSwapInterval;
805}
806
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000807D3DPOOL Renderer::getBufferPool(DWORD usage) const
808{
809 if (mD3d9Ex != NULL)
810 {
811 return D3DPOOL_DEFAULT;
812 }
813 else
814 {
815 if (!(usage & D3DUSAGE_DYNAMIC))
816 {
817 return D3DPOOL_MANAGED;
818 }
819 }
820
821 return D3DPOOL_DEFAULT;
822}
823
824D3DPOOL Renderer::getTexturePool(DWORD usage) const
825{
826 if (mD3d9Ex != NULL)
827 {
828 return D3DPOOL_DEFAULT;
829 }
830 else
831 {
832 if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)))
833 {
834 return D3DPOOL_MANAGED;
835 }
836 }
837
838 return D3DPOOL_DEFAULT;
839}
840
841}