blob: 4a26d4d378b509489800a8bc47dde19080c1f7d2 [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{
daniel@transgaming.com92955622012-10-31 18:38:41 +000029const D3DFORMAT Renderer::mRenderTargetFormats[] =
30 {
31 D3DFMT_A1R5G5B5,
32 // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
33 D3DFMT_A8R8G8B8,
34 D3DFMT_R5G6B5,
35 // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
36 D3DFMT_X8R8G8B8
37 };
38
39const D3DFORMAT Renderer::mDepthStencilFormats[] =
40 {
41 D3DFMT_UNKNOWN,
42 // D3DFMT_D16_LOCKABLE,
43 D3DFMT_D32,
44 // D3DFMT_D15S1,
45 D3DFMT_D24S8,
46 D3DFMT_D24X8,
47 // D3DFMT_D24X4S4,
48 D3DFMT_D16,
49 // D3DFMT_D32F_LOCKABLE,
50 // D3DFMT_D24FS8
51 };
daniel@transgaming.com621ce052012-10-31 17:52:29 +000052
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000053Renderer::Renderer(egl::Display *display, HMODULE hModule, HDC hDc): mDc(hDc)
daniel@transgaming.com621ce052012-10-31 17:52:29 +000054{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000055 mDisplay = display;
daniel@transgaming.com621ce052012-10-31 17:52:29 +000056 mD3d9Module = hModule;
57
58 mD3d9 = NULL;
59 mD3d9Ex = NULL;
60 mDevice = NULL;
61 mDeviceEx = NULL;
62 mDeviceWindow = NULL;
63
64 mAdapter = D3DADAPTER_DEFAULT;
65
66 #if REF_RAST == 1 || defined(FORCE_REF_RAST)
67 mDeviceType = D3DDEVTYPE_REF;
68 #else
69 mDeviceType = D3DDEVTYPE_HAL;
70 #endif
71
72 mDeviceLost = false;
daniel@transgaming.comb7833982012-10-31 18:31:46 +000073
74 mMaxSupportedSamples = 0;
daniel@transgaming.com621ce052012-10-31 17:52:29 +000075}
76
77Renderer::~Renderer()
78{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000079 releaseDeviceResources();
80
daniel@transgaming.com621ce052012-10-31 17:52:29 +000081 if (mDevice)
82 {
83 // 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 +000084 if (testDeviceLost(false))
daniel@transgaming.com621ce052012-10-31 17:52:29 +000085 {
86 resetDevice();
87 }
88
89 mDevice->Release();
90 mDevice = NULL;
91 }
92
93 if (mDeviceEx)
94 {
95 mDeviceEx->Release();
96 mDeviceEx = NULL;
97 }
98
99 if (mD3d9)
100 {
101 mD3d9->Release();
102 mD3d9 = NULL;
103 }
104
105 if (mDeviceWindow)
106 {
107 DestroyWindow(mDeviceWindow);
108 mDeviceWindow = NULL;
109 }
110
111 if (mD3d9Ex)
112 {
113 mD3d9Ex->Release();
114 mD3d9Ex = NULL;
115 }
116
117 if (mD3d9Module)
118 {
119 mD3d9Module = NULL;
120 }
121
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000122 while (!mMultiSampleSupport.empty())
123 {
124 delete [] mMultiSampleSupport.begin()->second;
125 mMultiSampleSupport.erase(mMultiSampleSupport.begin());
126 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000127}
128
129EGLint Renderer::initialize()
130{
131 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
132 Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
133
134 // Use Direct3D9Ex if available. Among other things, this version is less
135 // inclined to report a lost context, for example when the user switches
136 // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
137 if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
138 {
139 ASSERT(mD3d9Ex);
140 mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
141 ASSERT(mD3d9);
142 }
143 else
144 {
145 mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
146 }
147
148 if (!mD3d9)
149 {
150 ERR("Could not create D3D9 device - aborting!\n");
151 return EGL_NOT_INITIALIZED;
152 }
153 if (mDc != NULL)
154 {
155 // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
156 }
157
158 HRESULT result;
159
160 // Give up on getting device caps after about one second.
161 for (int i = 0; i < 10; ++i)
162 {
163 result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
164 if (SUCCEEDED(result))
165 {
166 break;
167 }
168 else if (result == D3DERR_NOTAVAILABLE)
169 {
170 Sleep(100); // Give the driver some time to initialize/recover
171 }
172 else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
173 {
174 ERR("failed to get device caps (0x%x)\n", result);
175 return EGL_NOT_INITIALIZED;
176 }
177 }
178
179 if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
180 {
181 ERR("Renderer does not support PS 2.0. aborting!\n");
182 return EGL_NOT_INITIALIZED;
183 }
184
185 // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
186 // This is required by Texture2D::convertToRenderTarget.
187 if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
188 {
189 ERR("Renderer does not support stretctrect from textures!\n");
190 return EGL_NOT_INITIALIZED;
191 }
192
193 mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
194
195 // ATI cards on XP have problems with non-power-of-two textures.
196 mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
197 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
198 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
199 !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD);
200
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000201 // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec
202 mSupportsTextureFilterAnisotropy = ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2));
203
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000204 mMinSwapInterval = 4;
205 mMaxSwapInterval = 0;
206
207 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)
208 {
209 mMinSwapInterval = std::min(mMinSwapInterval, 0);
210 mMaxSwapInterval = std::max(mMaxSwapInterval, 0);
211 }
212 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)
213 {
214 mMinSwapInterval = std::min(mMinSwapInterval, 1);
215 mMaxSwapInterval = std::max(mMaxSwapInterval, 1);
216 }
217 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)
218 {
219 mMinSwapInterval = std::min(mMinSwapInterval, 2);
220 mMaxSwapInterval = std::max(mMaxSwapInterval, 2);
221 }
222 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE)
223 {
224 mMinSwapInterval = std::min(mMinSwapInterval, 3);
225 mMaxSwapInterval = std::max(mMaxSwapInterval, 3);
226 }
227 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR)
228 {
229 mMinSwapInterval = std::min(mMinSwapInterval, 4);
230 mMaxSwapInterval = std::max(mMaxSwapInterval, 4);
231 }
232
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000233 int max = 0;
daniel@transgaming.com92955622012-10-31 18:38:41 +0000234 for (int i = 0; i < sizeof(mRenderTargetFormats) / sizeof(D3DFORMAT); ++i)
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000235 {
236 bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
daniel@transgaming.com92955622012-10-31 18:38:41 +0000237 getMultiSampleSupport(mRenderTargetFormats[i], multisampleArray);
238 mMultiSampleSupport[mRenderTargetFormats[i]] = multisampleArray;
239
240 for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
241 {
242 if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
243 {
244 max = j;
245 }
246 }
247 }
248
249 for (int i = 0; i < sizeof(mDepthStencilFormats) / sizeof(D3DFORMAT); ++i)
250 {
251 if (mDepthStencilFormats[i] == D3DFMT_UNKNOWN)
252 continue;
253
254 bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
255 getMultiSampleSupport(mDepthStencilFormats[i], multisampleArray);
256 mMultiSampleSupport[mDepthStencilFormats[i]] = multisampleArray;
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000257
258 for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
259 {
260 if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
261 {
262 max = j;
263 }
264 }
265 }
266
267 mMaxSupportedSamples = max;
268
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000269 static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
270 static const TCHAR className[] = TEXT("STATIC");
271
272 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
273
274 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
275 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
276
277 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
278 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
279 {
280 return EGL_BAD_ALLOC;
281 }
282
283 if (FAILED(result))
284 {
285 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
286
287 if (FAILED(result))
288 {
289 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
290 return EGL_BAD_ALLOC;
291 }
292 }
293
294 if (mD3d9Ex)
295 {
296 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
297 ASSERT(SUCCEEDED(result));
298 }
299
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000300 mVertexShaderCache.initialize(mDevice);
301 mPixelShaderCache.initialize(mDevice);
302
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000303 initializeDevice();
304
305 return EGL_SUCCESS;
306}
307
308// do any one-time device initialization
309// NOTE: this is also needed after a device lost/reset
310// to reset the scene status and ensure the default states are reset.
311void Renderer::initializeDevice()
312{
313 // Permanent non-default states
314 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
315 mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE);
316
317 if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
318 {
319 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize);
320 }
321 else
322 {
323 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f
324 }
325
326 mSceneStarted = false;
327}
328
329D3DPRESENT_PARAMETERS Renderer::getDefaultPresentParameters()
330{
331 D3DPRESENT_PARAMETERS presentParameters = {0};
332
333 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
334 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
335 presentParameters.BackBufferCount = 1;
336 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
337 presentParameters.BackBufferWidth = 1;
338 presentParameters.BackBufferHeight = 1;
339 presentParameters.EnableAutoDepthStencil = FALSE;
340 presentParameters.Flags = 0;
341 presentParameters.hDeviceWindow = mDeviceWindow;
342 presentParameters.MultiSampleQuality = 0;
343 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
344 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
345 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
346 presentParameters.Windowed = TRUE;
347
348 return presentParameters;
349}
350
351void Renderer::startScene()
352{
353 if (!mSceneStarted)
354 {
355 long result = mDevice->BeginScene();
356 if (SUCCEEDED(result)) {
357 // This is defensive checking against the device being
358 // lost at unexpected times.
359 mSceneStarted = true;
360 }
361 }
362}
363
364void Renderer::endScene()
365{
366 if (mSceneStarted)
367 {
368 // EndScene can fail if the device was lost, for example due
369 // to a TDR during a draw call.
370 mDevice->EndScene();
371 mSceneStarted = false;
372 }
373}
374
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000375// D3D9_REPLACE
376void Renderer::sync(bool block)
377{
378 HRESULT result;
379
380 IDirect3DQuery9* query = allocateEventQuery();
381 if (!query)
382 {
383 return;
384 }
385
386 result = query->Issue(D3DISSUE_END);
387 ASSERT(SUCCEEDED(result));
388
389 do
390 {
391 result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
392
393 if(block && result == S_FALSE)
394 {
395 // Keep polling, but allow other threads to do something useful first
396 Sleep(0);
397 // explicitly check for device loss
398 // some drivers seem to return S_FALSE even if the device is lost
399 // instead of D3DERR_DEVICELOST like they should
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000400 if (testDeviceLost(false))
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000401 {
402 result = D3DERR_DEVICELOST;
403 }
404 }
405 }
406 while(block && result == S_FALSE);
407
408 freeEventQuery(query);
409
410 if (isDeviceLostError(result))
411 {
412 mDisplay->notifyDeviceLost();
413 }
414}
415
416// D3D9_REPLACE
417IDirect3DQuery9* Renderer::allocateEventQuery()
418{
419 IDirect3DQuery9 *query = NULL;
420
421 if (mEventQueryPool.empty())
422 {
423 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
424 ASSERT(SUCCEEDED(result));
425 }
426 else
427 {
428 query = mEventQueryPool.back();
429 mEventQueryPool.pop_back();
430 }
431
432 return query;
433}
434
435// D3D9_REPLACE
436void Renderer::freeEventQuery(IDirect3DQuery9* query)
437{
438 if (mEventQueryPool.size() > 1000)
439 {
440 query->Release();
441 }
442 else
443 {
444 mEventQueryPool.push_back(query);
445 }
446}
447
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000448IDirect3DVertexShader9 *Renderer::createVertexShader(const DWORD *function, size_t length)
449{
450 return mVertexShaderCache.create(function, length);
451}
452
453IDirect3DPixelShader9 *Renderer::createPixelShader(const DWORD *function, size_t length)
454{
455 return mPixelShaderCache.create(function, length);
456}
457
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000458
459void Renderer::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState)
460{
461 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
462 int d3dSampler = index + d3dSamplerOffset;
463
464 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(samplerState.wrapS));
465 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(samplerState.wrapT));
466
467 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy));
468 D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
469 es2dx::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy);
470 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
471 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
472 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.lodOffset);
473 if (mSupportsTextureFilterAnisotropy)
474 {
475 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy);
476 }
477}
478
daniel@transgaming.coma734f272012-10-31 18:07:48 +0000479void Renderer::setTexture(gl::SamplerType type, int index, gl::Texture *texture)
480{
481 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
482 int d3dSampler = index + d3dSamplerOffset;
483 IDirect3DBaseTexture9 *d3dTexture = NULL;
484
485 if (texture)
486 {
487 d3dTexture = texture->getD3DTexture();
488 // If we get NULL back from getTexture here, something went wrong
489 // in the texture class and we're unexpectedly missing the d3d texture
490 ASSERT(d3dTexture != NULL);
491 }
492
493 mDevice->SetTexture(d3dSampler, d3dTexture);
494}
495
496
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000497void Renderer::releaseDeviceResources()
498{
499 while (!mEventQueryPool.empty())
500 {
501 mEventQueryPool.back()->Release();
502 mEventQueryPool.pop_back();
503 }
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000504
505 mVertexShaderCache.clear();
506 mPixelShaderCache.clear();
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000507}
508
509
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000510void Renderer::markDeviceLost()
511{
512 mDeviceLost = true;
513}
514
515bool Renderer::isDeviceLost()
516{
517 return mDeviceLost;
518}
519
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000520// set notify to true to broadcast a message to all contexts of the device loss
521bool Renderer::testDeviceLost(bool notify)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000522{
523 bool isLost = false;
524
525 if (mDeviceEx)
526 {
527 isLost = FAILED(mDeviceEx->CheckDeviceState(NULL));
528 }
529 else if (mDevice)
530 {
531 isLost = FAILED(mDevice->TestCooperativeLevel());
532 }
533 else
534 {
535 // No device yet, so no reset required
536 }
537
538 if (isLost)
539 {
540 // ensure we note the device loss --
541 // we'll probably get this done again by markDeviceLost
542 // but best to remember it!
543 // Note that we don't want to clear the device loss status here
544 // -- this needs to be done by resetDevice
545 mDeviceLost = true;
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000546 if (notify)
547 {
548 mDisplay->notifyDeviceLost();
549 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000550 }
551
552 return isLost;
553}
554
555bool Renderer::testDeviceResettable()
556{
557 HRESULT status = D3D_OK;
558
559 if (mDeviceEx)
560 {
561 status = mDeviceEx->CheckDeviceState(NULL);
562 }
563 else if (mDevice)
564 {
565 status = mDevice->TestCooperativeLevel();
566 }
567
568 switch (status)
569 {
570 case D3DERR_DEVICENOTRESET:
571 case D3DERR_DEVICEHUNG:
572 return true;
573 default:
574 return false;
575 }
576}
577
578bool Renderer::resetDevice()
579{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000580 releaseDeviceResources();
581
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000582 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
583
584 HRESULT result = D3D_OK;
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000585 bool lost = testDeviceLost(false);
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000586 int attempts = 3;
587
588 while (lost && attempts > 0)
589 {
590 if (mDeviceEx)
591 {
592 Sleep(500); // Give the graphics driver some CPU time
593 result = mDeviceEx->ResetEx(&presentParameters, NULL);
594 }
595 else
596 {
597 result = mDevice->TestCooperativeLevel();
598 while (result == D3DERR_DEVICELOST)
599 {
600 Sleep(100); // Give the graphics driver some CPU time
601 result = mDevice->TestCooperativeLevel();
602 }
603
604 if (result == D3DERR_DEVICENOTRESET)
605 {
606 result = mDevice->Reset(&presentParameters);
607 }
608 }
609
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000610 lost = testDeviceLost(false);
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000611 attempts --;
612 }
613
614 if (FAILED(result))
615 {
616 ERR("Reset/ResetEx failed multiple times: 0x%08X", result);
617 return false;
618 }
619
620 // reset device defaults
621 initializeDevice();
622 mDeviceLost = false;
623
624 return true;
625}
626
627void Renderer::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
628{
629 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
630 {
631 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
632 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
633
634 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
635 }
636}
637
638bool Renderer::getDXT1TextureSupport()
639{
640 D3DDISPLAYMODE currentDisplayMode;
641 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
642
643 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
644}
645
646bool Renderer::getDXT3TextureSupport()
647{
648 D3DDISPLAYMODE currentDisplayMode;
649 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
650
651 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3));
652}
653
654bool Renderer::getDXT5TextureSupport()
655{
656 D3DDISPLAYMODE currentDisplayMode;
657 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
658
659 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5));
660}
661
662// we use INTZ for depth textures in Direct3D9
663// we also want NULL texture support to ensure the we can make depth-only FBOs
664// see http://aras-p.info/texts/D3D9GPUHacks.html
665bool Renderer::getDepthTextureSupport() const
666{
667 D3DDISPLAYMODE currentDisplayMode;
668 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
669
670 bool intz = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
671 D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ));
672 bool null = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
673 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL));
674
675 return intz && null;
676}
677
678bool Renderer::getFloat32TextureSupport(bool *filtering, bool *renderable)
679{
680 D3DDISPLAYMODE currentDisplayMode;
681 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
682
683 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
684 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
685 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
686 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
687
688 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
689 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
690 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
691 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
692
693 if (!*filtering && !*renderable)
694 {
695 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
696 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
697 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
698 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
699 }
700 else
701 {
702 return true;
703 }
704}
705
706bool Renderer::getFloat16TextureSupport(bool *filtering, bool *renderable)
707{
708 D3DDISPLAYMODE currentDisplayMode;
709 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
710
711 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
712 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
713 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
714 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
715
716 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
717 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
718 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
719 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
720
721 if (!*filtering && !*renderable)
722 {
723 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
724 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
725 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
726 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
727 }
728 else
729 {
730 return true;
731 }
732}
733
734bool Renderer::getLuminanceTextureSupport()
735{
736 D3DDISPLAYMODE currentDisplayMode;
737 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
738
739 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
740}
741
742bool Renderer::getLuminanceAlphaTextureSupport()
743{
744 D3DDISPLAYMODE currentDisplayMode;
745 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
746
747 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
748}
749
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000750bool Renderer::getTextureFilterAnisotropySupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000751{
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000752 return mSupportsTextureFilterAnisotropy;
753}
754
755float Renderer::getTextureMaxAnisotropy() const
756{
757 if (mSupportsTextureFilterAnisotropy)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000758 {
759 return mDeviceCaps.MaxAnisotropy;
760 }
761 return 1.0f;
762}
763
764bool Renderer::getEventQuerySupport()
765{
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000766 IDirect3DQuery9 *query = allocateEventQuery();
767 if (query)
768 {
769 freeEventQuery(query);
770 return true;
771 }
772 else
773 {
774 return false;
775 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000776 return true;
777}
778
779// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
780// We test this using D3D9 by checking support for the R16F format.
781bool Renderer::getVertexTextureSupport() const
782{
783 if (!mDevice || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
784 {
785 return false;
786 }
787
788 D3DDISPLAYMODE currentDisplayMode;
789 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
790
791 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
792
793 return SUCCEEDED(result);
794}
795
796bool Renderer::getNonPower2TextureSupport() const
797{
798 return mSupportsNonPower2Textures;
799}
800
801bool Renderer::getOcclusionQuerySupport() const
802{
803 if (!mDevice)
804 {
805 return false;
806 }
807
808 IDirect3DQuery9 *query = NULL;
809 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query);
810 if (SUCCEEDED(result) && query)
811 {
812 query->Release();
813 return true;
814 }
815 else
816 {
817 return false;
818 }
819}
820
821bool Renderer::getInstancingSupport() const
822{
823 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
824}
825
daniel@transgaming.com313e3922012-10-31 17:52:39 +0000826bool Renderer::getShareHandleSupport() const
827{
828 // PIX doesn't seem to support using share handles, so disable them.
829 // D3D9_REPLACE
830 return isD3d9ExDevice() && !gl::perfActive();
831}
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000832
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000833bool Renderer::getShaderModel3Support() const
834{
835 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
836}
837
838float Renderer::getMaxPointSize() const
839{
840 return mDeviceCaps.MaxPointSize;
841}
842
843int Renderer::getMaxTextureWidth() const
844{
845 return (int)mDeviceCaps.MaxTextureWidth;
846}
847
848int Renderer::getMaxTextureHeight() const
849{
850 return (int)mDeviceCaps.MaxTextureHeight;
851}
852
853bool Renderer::get32BitIndexSupport() const
854{
855 return mDeviceCaps.MaxVertexIndex >= (1 << 16);
856}
857
858DWORD Renderer::getCapsDeclTypes() const
859{
860 return mDeviceCaps.DeclTypes;
861}
862
863int Renderer::getMinSwapInterval() const
864{
865 return mMinSwapInterval;
866}
867
868int Renderer::getMaxSwapInterval() const
869{
870 return mMaxSwapInterval;
871}
872
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000873int Renderer::getMaxSupportedSamples() const
874{
875 return mMaxSupportedSamples;
876}
877
878int Renderer::getNearestSupportedSamples(D3DFORMAT format, int requested) const
879{
880 if (requested == 0)
881 {
882 return requested;
883 }
884
885 std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format);
886 if (itr == mMultiSampleSupport.end())
887 {
daniel@transgaming.com92955622012-10-31 18:38:41 +0000888 if (format == D3DFMT_UNKNOWN)
889 return 0;
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000890 return -1;
891 }
892
893 for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i)
894 {
895 if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE)
896 {
897 return i;
898 }
899 }
900
901 return -1;
902}
903
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000904D3DPOOL Renderer::getBufferPool(DWORD usage) const
905{
906 if (mD3d9Ex != NULL)
907 {
908 return D3DPOOL_DEFAULT;
909 }
910 else
911 {
912 if (!(usage & D3DUSAGE_DYNAMIC))
913 {
914 return D3DPOOL_MANAGED;
915 }
916 }
917
918 return D3DPOOL_DEFAULT;
919}
920
921D3DPOOL Renderer::getTexturePool(DWORD usage) const
922{
923 if (mD3d9Ex != NULL)
924 {
925 return D3DPOOL_DEFAULT;
926 }
927 else
928 {
929 if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)))
930 {
931 return D3DPOOL_MANAGED;
932 }
933 }
934
935 return D3DPOOL_DEFAULT;
936}
937
938}