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