blob: 0254b84a1abb2e5725ae9805d573e44bbfad7fe4 [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
daniel@transgaming.com1d6aff22012-11-28 19:30:42 +00007// Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer.
daniel@transgaming.com621ce052012-10-31 17:52:29 +00008
daniel@transgaming.com621ce052012-10-31 17:52:29 +00009#include "common/debug.h"
10#include "libGLESv2/utilities.h"
daniel@transgaming.com2507f412012-10-31 18:46:48 +000011#include "libGLESv2/renderer/Renderer9.h"
daniel@transgaming.comd8e36562012-10-31 19:52:19 +000012#include "libGLESv2/renderer/renderer9_utils.h"
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +000013#include "libGLESv2/renderer/TextureStorage.h"
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +000014#include "libGLESv2/renderer/Image.h"
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +000015#include "libGLESv2/renderer/Blit.h"
daniel@transgaming.com621ce052012-10-31 17:52:29 +000016
daniel@transgaming.com3281f972012-10-31 18:38:51 +000017#include "libEGL/Config.h"
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000018#include "libEGL/Display.h"
19
daniel@transgaming.com621ce052012-10-31 17:52:29 +000020// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
21#define REF_RAST 0
22
23// The "Debug This Pixel..." feature in PIX often fails when using the
24// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7
25// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file.
26#if !defined(ANGLE_ENABLE_D3D9EX)
27// Enables use of the IDirect3D9Ex interface, when available
28#define ANGLE_ENABLE_D3D9EX 1
29#endif // !defined(ANGLE_ENABLE_D3D9EX)
30
daniel@transgaming.com76d3e6e2012-10-31 19:55:33 +000031namespace rx
daniel@transgaming.com621ce052012-10-31 17:52:29 +000032{
daniel@transgaming.com222ee082012-11-28 19:31:49 +000033static const D3DFORMAT RenderTargetFormats[] =
daniel@transgaming.com92955622012-10-31 18:38:41 +000034 {
35 D3DFMT_A1R5G5B5,
36 // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
37 D3DFMT_A8R8G8B8,
38 D3DFMT_R5G6B5,
39 // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
40 D3DFMT_X8R8G8B8
41 };
42
daniel@transgaming.com222ee082012-11-28 19:31:49 +000043static const D3DFORMAT DepthStencilFormats[] =
daniel@transgaming.com92955622012-10-31 18:38:41 +000044 {
45 D3DFMT_UNKNOWN,
46 // D3DFMT_D16_LOCKABLE,
47 D3DFMT_D32,
48 // D3DFMT_D15S1,
49 D3DFMT_D24S8,
50 D3DFMT_D24X8,
51 // D3DFMT_D24X4S4,
52 D3DFMT_D16,
53 // D3DFMT_D32F_LOCKABLE,
54 // D3DFMT_D24FS8
55 };
daniel@transgaming.com621ce052012-10-31 17:52:29 +000056
daniel@transgaming.com95ffbc12012-10-31 19:55:27 +000057Renderer9::Renderer9(egl::Display *display, HDC hDc, bool softwareDevice) : Renderer(display), mDc(hDc), mSoftwareDevice(softwareDevice)
daniel@transgaming.com621ce052012-10-31 17:52:29 +000058{
daniel@transgaming.com95ffbc12012-10-31 19:55:27 +000059 mD3d9Module = NULL;
daniel@transgaming.com621ce052012-10-31 17:52:29 +000060
61 mD3d9 = NULL;
62 mD3d9Ex = NULL;
63 mDevice = NULL;
64 mDeviceEx = NULL;
65 mDeviceWindow = NULL;
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +000066 mBlit = NULL;
daniel@transgaming.com621ce052012-10-31 17:52:29 +000067
68 mAdapter = D3DADAPTER_DEFAULT;
69
70 #if REF_RAST == 1 || defined(FORCE_REF_RAST)
71 mDeviceType = D3DDEVTYPE_REF;
72 #else
73 mDeviceType = D3DDEVTYPE_HAL;
74 #endif
75
76 mDeviceLost = false;
daniel@transgaming.comb7833982012-10-31 18:31:46 +000077
78 mMaxSupportedSamples = 0;
daniel@transgaming.com621ce052012-10-31 17:52:29 +000079}
80
daniel@transgaming.com2507f412012-10-31 18:46:48 +000081Renderer9::~Renderer9()
daniel@transgaming.com621ce052012-10-31 17:52:29 +000082{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000083 releaseDeviceResources();
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +000084
85 delete mBlit;
daniel@transgaming.comef21ab22012-10-31 17:52:47 +000086
daniel@transgaming.com621ce052012-10-31 17:52:29 +000087 if (mDevice)
88 {
89 // 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 +000090 if (testDeviceLost(false))
daniel@transgaming.com621ce052012-10-31 17:52:29 +000091 {
92 resetDevice();
93 }
94
95 mDevice->Release();
96 mDevice = NULL;
97 }
98
99 if (mDeviceEx)
100 {
101 mDeviceEx->Release();
102 mDeviceEx = NULL;
103 }
104
105 if (mD3d9)
106 {
107 mD3d9->Release();
108 mD3d9 = NULL;
109 }
110
111 if (mDeviceWindow)
112 {
113 DestroyWindow(mDeviceWindow);
114 mDeviceWindow = NULL;
115 }
116
117 if (mD3d9Ex)
118 {
119 mD3d9Ex->Release();
120 mD3d9Ex = NULL;
121 }
122
123 if (mD3d9Module)
124 {
125 mD3d9Module = NULL;
126 }
127
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000128 while (!mMultiSampleSupport.empty())
129 {
130 delete [] mMultiSampleSupport.begin()->second;
131 mMultiSampleSupport.erase(mMultiSampleSupport.begin());
132 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000133}
134
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000135EGLint Renderer9::initialize()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000136{
daniel@transgaming.com95ffbc12012-10-31 19:55:27 +0000137 if (mSoftwareDevice)
138 {
139 mD3d9Module = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
140 }
141 else
142 {
143 mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
144 }
145
146 if (mD3d9Module == NULL)
147 {
148 ERR("No D3D9 module found - aborting!\n");
149 return EGL_NOT_INITIALIZED;
150 }
151
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000152 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
153 Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
154
155 // Use Direct3D9Ex if available. Among other things, this version is less
156 // inclined to report a lost context, for example when the user switches
157 // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
158 if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
159 {
160 ASSERT(mD3d9Ex);
161 mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
162 ASSERT(mD3d9);
163 }
164 else
165 {
166 mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
167 }
168
169 if (!mD3d9)
170 {
171 ERR("Could not create D3D9 device - aborting!\n");
172 return EGL_NOT_INITIALIZED;
173 }
174 if (mDc != NULL)
175 {
176 // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
177 }
178
179 HRESULT result;
180
181 // Give up on getting device caps after about one second.
182 for (int i = 0; i < 10; ++i)
183 {
184 result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
185 if (SUCCEEDED(result))
186 {
187 break;
188 }
189 else if (result == D3DERR_NOTAVAILABLE)
190 {
191 Sleep(100); // Give the driver some time to initialize/recover
192 }
193 else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
194 {
195 ERR("failed to get device caps (0x%x)\n", result);
196 return EGL_NOT_INITIALIZED;
197 }
198 }
199
200 if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
201 {
202 ERR("Renderer does not support PS 2.0. aborting!\n");
203 return EGL_NOT_INITIALIZED;
204 }
205
206 // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
207 // This is required by Texture2D::convertToRenderTarget.
208 if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
209 {
210 ERR("Renderer does not support stretctrect from textures!\n");
211 return EGL_NOT_INITIALIZED;
212 }
213
214 mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
215
216 // ATI cards on XP have problems with non-power-of-two textures.
217 mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
218 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
219 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
220 !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD);
221
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000222 // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec
223 mSupportsTextureFilterAnisotropy = ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2));
224
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000225 mMinSwapInterval = 4;
226 mMaxSwapInterval = 0;
227
228 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)
229 {
230 mMinSwapInterval = std::min(mMinSwapInterval, 0);
231 mMaxSwapInterval = std::max(mMaxSwapInterval, 0);
232 }
233 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)
234 {
235 mMinSwapInterval = std::min(mMinSwapInterval, 1);
236 mMaxSwapInterval = std::max(mMaxSwapInterval, 1);
237 }
238 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)
239 {
240 mMinSwapInterval = std::min(mMinSwapInterval, 2);
241 mMaxSwapInterval = std::max(mMaxSwapInterval, 2);
242 }
243 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE)
244 {
245 mMinSwapInterval = std::min(mMinSwapInterval, 3);
246 mMaxSwapInterval = std::max(mMaxSwapInterval, 3);
247 }
248 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR)
249 {
250 mMinSwapInterval = std::min(mMinSwapInterval, 4);
251 mMaxSwapInterval = std::max(mMaxSwapInterval, 4);
252 }
253
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000254 int max = 0;
daniel@transgaming.com222ee082012-11-28 19:31:49 +0000255 for (int i = 0; i < sizeof(RenderTargetFormats) / sizeof(D3DFORMAT); ++i)
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000256 {
257 bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
daniel@transgaming.com222ee082012-11-28 19:31:49 +0000258 getMultiSampleSupport(RenderTargetFormats[i], multisampleArray);
259 mMultiSampleSupport[RenderTargetFormats[i]] = multisampleArray;
daniel@transgaming.com92955622012-10-31 18:38:41 +0000260
261 for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
262 {
263 if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
264 {
265 max = j;
266 }
267 }
268 }
269
daniel@transgaming.com222ee082012-11-28 19:31:49 +0000270 for (int i = 0; i < sizeof(DepthStencilFormats) / sizeof(D3DFORMAT); ++i)
daniel@transgaming.com92955622012-10-31 18:38:41 +0000271 {
daniel@transgaming.com222ee082012-11-28 19:31:49 +0000272 if (DepthStencilFormats[i] == D3DFMT_UNKNOWN)
daniel@transgaming.com92955622012-10-31 18:38:41 +0000273 continue;
274
275 bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
daniel@transgaming.com222ee082012-11-28 19:31:49 +0000276 getMultiSampleSupport(DepthStencilFormats[i], multisampleArray);
277 mMultiSampleSupport[DepthStencilFormats[i]] = multisampleArray;
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000278
279 for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
280 {
281 if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
282 {
283 max = j;
284 }
285 }
286 }
287
288 mMaxSupportedSamples = max;
289
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000290 static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
291 static const TCHAR className[] = TEXT("STATIC");
292
293 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
294
295 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
296 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
297
298 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
299 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
300 {
301 return EGL_BAD_ALLOC;
302 }
303
304 if (FAILED(result))
305 {
306 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
307
308 if (FAILED(result))
309 {
310 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
311 return EGL_BAD_ALLOC;
312 }
313 }
314
315 if (mD3d9Ex)
316 {
317 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
318 ASSERT(SUCCEEDED(result));
319 }
320
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000321 mVertexShaderCache.initialize(mDevice);
322 mPixelShaderCache.initialize(mDevice);
323
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000324 initializeDevice();
325
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000326 mBlit = new Blit(this);
327
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000328 return EGL_SUCCESS;
329}
330
331// do any one-time device initialization
332// NOTE: this is also needed after a device lost/reset
333// to reset the scene status and ensure the default states are reset.
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000334void Renderer9::initializeDevice()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000335{
336 // Permanent non-default states
337 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
338 mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE);
339
340 if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
341 {
342 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize);
343 }
344 else
345 {
346 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f
347 }
348
349 mSceneStarted = false;
350}
351
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000352D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000353{
354 D3DPRESENT_PARAMETERS presentParameters = {0};
355
356 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
357 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
358 presentParameters.BackBufferCount = 1;
359 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
360 presentParameters.BackBufferWidth = 1;
361 presentParameters.BackBufferHeight = 1;
362 presentParameters.EnableAutoDepthStencil = FALSE;
363 presentParameters.Flags = 0;
364 presentParameters.hDeviceWindow = mDeviceWindow;
365 presentParameters.MultiSampleQuality = 0;
366 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
367 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
368 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
369 presentParameters.Windowed = TRUE;
370
371 return presentParameters;
372}
373
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000374int Renderer9::generateConfigs(ConfigDesc **configDescList)
daniel@transgaming.com3281f972012-10-31 18:38:51 +0000375{
376 D3DDISPLAYMODE currentDisplayMode;
377 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
378
daniel@transgaming.com222ee082012-11-28 19:31:49 +0000379 int numRenderFormats = sizeof(RenderTargetFormats) / sizeof(RenderTargetFormats[0]);
380 int numDepthFormats = sizeof(DepthStencilFormats) / sizeof(DepthStencilFormats[0]);
daniel@transgaming.com3281f972012-10-31 18:38:51 +0000381 (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats];
382 int numConfigs = 0;
383
384 for (int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++)
385 {
daniel@transgaming.com222ee082012-11-28 19:31:49 +0000386 D3DFORMAT renderTargetFormat = RenderTargetFormats[formatIndex];
daniel@transgaming.com3281f972012-10-31 18:38:51 +0000387
388 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
389
390 if (SUCCEEDED(result))
391 {
392 for (int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++)
393 {
daniel@transgaming.com222ee082012-11-28 19:31:49 +0000394 D3DFORMAT depthStencilFormat = DepthStencilFormats[depthStencilIndex];
daniel@transgaming.com3281f972012-10-31 18:38:51 +0000395 HRESULT result = D3D_OK;
396
397 if(depthStencilFormat != D3DFMT_UNKNOWN)
398 {
399 result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
400 }
401
402 if (SUCCEEDED(result))
403 {
404 if(depthStencilFormat != D3DFMT_UNKNOWN)
405 {
406 result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
407 }
408
409 if (SUCCEEDED(result))
410 {
411 ConfigDesc newConfig;
412 newConfig.renderTargetFormat = dx2es::ConvertBackBufferFormat(renderTargetFormat);
413 newConfig.depthStencilFormat = dx2es::ConvertDepthStencilFormat(depthStencilFormat);
414 newConfig.multiSample = 0; // FIXME: enumerate multi-sampling
415 newConfig.fastConfig = (currentDisplayMode.Format == renderTargetFormat);
416
417 (*configDescList)[numConfigs++] = newConfig;
418 }
419 }
420 }
421 }
422 }
423
424 return numConfigs;
425}
426
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000427void Renderer9::deleteConfigs(ConfigDesc *configDescList)
daniel@transgaming.com3281f972012-10-31 18:38:51 +0000428{
429 delete [] (configDescList);
430}
431
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000432void Renderer9::startScene()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000433{
434 if (!mSceneStarted)
435 {
436 long result = mDevice->BeginScene();
437 if (SUCCEEDED(result)) {
438 // This is defensive checking against the device being
439 // lost at unexpected times.
440 mSceneStarted = true;
441 }
442 }
443}
444
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000445void Renderer9::endScene()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000446{
447 if (mSceneStarted)
448 {
449 // EndScene can fail if the device was lost, for example due
450 // to a TDR during a draw call.
451 mDevice->EndScene();
452 mSceneStarted = false;
453 }
454}
455
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000456// D3D9_REPLACE
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000457void Renderer9::sync(bool block)
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000458{
459 HRESULT result;
460
461 IDirect3DQuery9* query = allocateEventQuery();
462 if (!query)
463 {
464 return;
465 }
466
467 result = query->Issue(D3DISSUE_END);
468 ASSERT(SUCCEEDED(result));
469
470 do
471 {
472 result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
473
474 if(block && result == S_FALSE)
475 {
476 // Keep polling, but allow other threads to do something useful first
477 Sleep(0);
478 // explicitly check for device loss
479 // some drivers seem to return S_FALSE even if the device is lost
480 // instead of D3DERR_DEVICELOST like they should
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000481 if (testDeviceLost(false))
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000482 {
483 result = D3DERR_DEVICELOST;
484 }
485 }
486 }
487 while(block && result == S_FALSE);
488
489 freeEventQuery(query);
490
491 if (isDeviceLostError(result))
492 {
493 mDisplay->notifyDeviceLost();
494 }
495}
496
497// D3D9_REPLACE
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000498IDirect3DQuery9* Renderer9::allocateEventQuery()
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000499{
500 IDirect3DQuery9 *query = NULL;
501
502 if (mEventQueryPool.empty())
503 {
504 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
505 ASSERT(SUCCEEDED(result));
506 }
507 else
508 {
509 query = mEventQueryPool.back();
510 mEventQueryPool.pop_back();
511 }
512
513 return query;
514}
515
516// D3D9_REPLACE
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000517void Renderer9::freeEventQuery(IDirect3DQuery9* query)
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000518{
519 if (mEventQueryPool.size() > 1000)
520 {
521 query->Release();
522 }
523 else
524 {
525 mEventQueryPool.push_back(query);
526 }
527}
528
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000529IDirect3DVertexShader9 *Renderer9::createVertexShader(const DWORD *function, size_t length)
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000530{
531 return mVertexShaderCache.create(function, length);
532}
533
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000534IDirect3DPixelShader9 *Renderer9::createPixelShader(const DWORD *function, size_t length)
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000535{
536 return mPixelShaderCache.create(function, length);
537}
538
daniel@transgaming.com113f0eb2012-10-31 18:46:58 +0000539HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer)
540{
541 D3DPOOL Pool = getBufferPool(Usage);
542 return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL);
543}
544
545HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer)
546{
547 D3DPOOL Pool = getBufferPool(Usage);
548 return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL);
549}
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000550
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000551void Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState)
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000552{
553 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
554 int d3dSampler = index + d3dSamplerOffset;
555
556 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(samplerState.wrapS));
557 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(samplerState.wrapT));
558
559 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy));
560 D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
561 es2dx::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy);
562 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
563 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
564 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.lodOffset);
565 if (mSupportsTextureFilterAnisotropy)
566 {
567 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy);
568 }
569}
570
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000571void Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture)
daniel@transgaming.coma734f272012-10-31 18:07:48 +0000572{
573 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
574 int d3dSampler = index + d3dSamplerOffset;
575 IDirect3DBaseTexture9 *d3dTexture = NULL;
576
577 if (texture)
578 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000579 gl::TextureStorage *texStorage = texture->getNativeTexture();
580 if (texStorage)
581 {
582 d3dTexture = texStorage->getBaseTexture();
583 }
584 // If we get NULL back from getBaseTexture here, something went wrong
daniel@transgaming.coma734f272012-10-31 18:07:48 +0000585 // in the texture class and we're unexpectedly missing the d3d texture
586 ASSERT(d3dTexture != NULL);
587 }
588
589 mDevice->SetTexture(d3dSampler, d3dTexture);
590}
591
592
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000593void Renderer9::releaseDeviceResources()
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000594{
595 while (!mEventQueryPool.empty())
596 {
597 mEventQueryPool.back()->Release();
598 mEventQueryPool.pop_back();
599 }
daniel@transgaming.come4733d72012-10-31 18:07:01 +0000600
601 mVertexShaderCache.clear();
602 mPixelShaderCache.clear();
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000603}
604
605
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000606void Renderer9::markDeviceLost()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000607{
608 mDeviceLost = true;
609}
610
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000611bool Renderer9::isDeviceLost()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000612{
613 return mDeviceLost;
614}
615
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000616// set notify to true to broadcast a message to all contexts of the device loss
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000617bool Renderer9::testDeviceLost(bool notify)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000618{
619 bool isLost = false;
620
621 if (mDeviceEx)
622 {
623 isLost = FAILED(mDeviceEx->CheckDeviceState(NULL));
624 }
625 else if (mDevice)
626 {
627 isLost = FAILED(mDevice->TestCooperativeLevel());
628 }
629 else
630 {
631 // No device yet, so no reset required
632 }
633
634 if (isLost)
635 {
636 // ensure we note the device loss --
637 // we'll probably get this done again by markDeviceLost
638 // but best to remember it!
639 // Note that we don't want to clear the device loss status here
640 // -- this needs to be done by resetDevice
641 mDeviceLost = true;
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000642 if (notify)
643 {
644 mDisplay->notifyDeviceLost();
645 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000646 }
647
648 return isLost;
649}
650
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000651bool Renderer9::testDeviceResettable()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000652{
653 HRESULT status = D3D_OK;
654
655 if (mDeviceEx)
656 {
657 status = mDeviceEx->CheckDeviceState(NULL);
658 }
659 else if (mDevice)
660 {
661 status = mDevice->TestCooperativeLevel();
662 }
663
664 switch (status)
665 {
666 case D3DERR_DEVICENOTRESET:
667 case D3DERR_DEVICEHUNG:
668 return true;
669 default:
670 return false;
671 }
672}
673
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000674bool Renderer9::resetDevice()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000675{
daniel@transgaming.comef21ab22012-10-31 17:52:47 +0000676 releaseDeviceResources();
677
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000678 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
679
680 HRESULT result = D3D_OK;
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000681 bool lost = testDeviceLost(false);
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000682 int attempts = 3;
683
684 while (lost && attempts > 0)
685 {
686 if (mDeviceEx)
687 {
688 Sleep(500); // Give the graphics driver some CPU time
689 result = mDeviceEx->ResetEx(&presentParameters, NULL);
690 }
691 else
692 {
693 result = mDevice->TestCooperativeLevel();
694 while (result == D3DERR_DEVICELOST)
695 {
696 Sleep(100); // Give the graphics driver some CPU time
697 result = mDevice->TestCooperativeLevel();
698 }
699
700 if (result == D3DERR_DEVICENOTRESET)
701 {
702 result = mDevice->Reset(&presentParameters);
703 }
704 }
705
daniel@transgaming.comf688c0d2012-10-31 17:52:57 +0000706 lost = testDeviceLost(false);
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000707 attempts --;
708 }
709
710 if (FAILED(result))
711 {
712 ERR("Reset/ResetEx failed multiple times: 0x%08X", result);
713 return false;
714 }
715
716 // reset device defaults
717 initializeDevice();
718 mDeviceLost = false;
719
720 return true;
721}
722
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000723DWORD Renderer9::getAdapterVendor() const
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +0000724{
725 return mAdapterIdentifier.VendorId;
726}
727
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000728const char *Renderer9::getAdapterDescription() const
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +0000729{
730 return mAdapterIdentifier.Description;
731}
732
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000733GUID Renderer9::getAdapterIdentifier() const
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +0000734{
735 return mAdapterIdentifier.DeviceIdentifier;
736}
737
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000738void Renderer9::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000739{
740 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
741 {
742 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
743 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
744
745 multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
746 }
747}
748
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000749bool Renderer9::getDXT1TextureSupport()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000750{
751 D3DDISPLAYMODE currentDisplayMode;
752 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
753
754 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
755}
756
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000757bool Renderer9::getDXT3TextureSupport()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000758{
759 D3DDISPLAYMODE currentDisplayMode;
760 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
761
762 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3));
763}
764
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000765bool Renderer9::getDXT5TextureSupport()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000766{
767 D3DDISPLAYMODE currentDisplayMode;
768 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
769
770 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5));
771}
772
773// we use INTZ for depth textures in Direct3D9
774// we also want NULL texture support to ensure the we can make depth-only FBOs
775// see http://aras-p.info/texts/D3D9GPUHacks.html
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000776bool Renderer9::getDepthTextureSupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000777{
778 D3DDISPLAYMODE currentDisplayMode;
779 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
780
781 bool intz = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
782 D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ));
783 bool null = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
784 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL));
785
786 return intz && null;
787}
788
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000789bool Renderer9::getFloat32TextureSupport(bool *filtering, bool *renderable)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000790{
791 D3DDISPLAYMODE currentDisplayMode;
792 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
793
794 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
795 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
796 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
797 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
798
799 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
800 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
801 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
802 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
803
804 if (!*filtering && !*renderable)
805 {
806 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
807 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
808 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
809 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
810 }
811 else
812 {
813 return true;
814 }
815}
816
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000817bool Renderer9::getFloat16TextureSupport(bool *filtering, bool *renderable)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000818{
819 D3DDISPLAYMODE currentDisplayMode;
820 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
821
822 *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
823 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
824 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
825 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
826
827 *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
828 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
829 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
830 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
831
832 if (!*filtering && !*renderable)
833 {
834 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
835 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
836 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
837 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
838 }
839 else
840 {
841 return true;
842 }
843}
844
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000845bool Renderer9::getLuminanceTextureSupport()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000846{
847 D3DDISPLAYMODE currentDisplayMode;
848 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
849
850 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
851}
852
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000853bool Renderer9::getLuminanceAlphaTextureSupport()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000854{
855 D3DDISPLAYMODE currentDisplayMode;
856 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
857
858 return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
859}
860
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000861bool Renderer9::getTextureFilterAnisotropySupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000862{
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000863 return mSupportsTextureFilterAnisotropy;
864}
865
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000866float Renderer9::getTextureMaxAnisotropy() const
daniel@transgaming.comba0570e2012-10-31 18:07:39 +0000867{
868 if (mSupportsTextureFilterAnisotropy)
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000869 {
870 return mDeviceCaps.MaxAnisotropy;
871 }
872 return 1.0f;
873}
874
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000875bool Renderer9::getEventQuerySupport()
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000876{
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000877 IDirect3DQuery9 *query = allocateEventQuery();
878 if (query)
879 {
880 freeEventQuery(query);
881 return true;
882 }
883 else
884 {
885 return false;
886 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000887 return true;
888}
889
890// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
891// We test this using D3D9 by checking support for the R16F format.
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000892bool Renderer9::getVertexTextureSupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000893{
894 if (!mDevice || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
895 {
896 return false;
897 }
898
899 D3DDISPLAYMODE currentDisplayMode;
900 mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
901
902 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
903
904 return SUCCEEDED(result);
905}
906
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000907bool Renderer9::getNonPower2TextureSupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000908{
909 return mSupportsNonPower2Textures;
910}
911
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000912bool Renderer9::getOcclusionQuerySupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000913{
914 if (!mDevice)
915 {
916 return false;
917 }
918
919 IDirect3DQuery9 *query = NULL;
920 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query);
921 if (SUCCEEDED(result) && query)
922 {
923 query->Release();
924 return true;
925 }
926 else
927 {
928 return false;
929 }
930}
931
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000932bool Renderer9::getInstancingSupport() const
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000933{
934 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
935}
936
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000937bool Renderer9::getShareHandleSupport() const
daniel@transgaming.com313e3922012-10-31 17:52:39 +0000938{
939 // PIX doesn't seem to support using share handles, so disable them.
940 // D3D9_REPLACE
daniel@transgaming.com7cb796e2012-10-31 18:46:44 +0000941 return (mD3d9Ex != NULL) && !gl::perfActive();
daniel@transgaming.com313e3922012-10-31 17:52:39 +0000942}
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000943
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000944bool Renderer9::getShaderModel3Support() const
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000945{
946 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
947}
948
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000949float Renderer9::getMaxPointSize() const
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000950{
951 return mDeviceCaps.MaxPointSize;
952}
953
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000954int Renderer9::getMaxTextureWidth() const
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000955{
956 return (int)mDeviceCaps.MaxTextureWidth;
957}
958
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000959int Renderer9::getMaxTextureHeight() const
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000960{
961 return (int)mDeviceCaps.MaxTextureHeight;
962}
963
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000964bool Renderer9::get32BitIndexSupport() const
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000965{
966 return mDeviceCaps.MaxVertexIndex >= (1 << 16);
967}
968
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000969DWORD Renderer9::getCapsDeclTypes() const
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000970{
971 return mDeviceCaps.DeclTypes;
972}
973
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000974int Renderer9::getMinSwapInterval() const
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000975{
976 return mMinSwapInterval;
977}
978
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000979int Renderer9::getMaxSwapInterval() const
daniel@transgaming.com5f4c1362012-10-31 18:29:00 +0000980{
981 return mMaxSwapInterval;
982}
983
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000984int Renderer9::getMaxSupportedSamples() const
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000985{
986 return mMaxSupportedSamples;
987}
988
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000989int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const
daniel@transgaming.comb7833982012-10-31 18:31:46 +0000990{
991 if (requested == 0)
992 {
993 return requested;
994 }
995
996 std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format);
997 if (itr == mMultiSampleSupport.end())
998 {
daniel@transgaming.com92955622012-10-31 18:38:41 +0000999 if (format == D3DFMT_UNKNOWN)
1000 return 0;
daniel@transgaming.comb7833982012-10-31 18:31:46 +00001001 return -1;
1002 }
1003
1004 for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i)
1005 {
1006 if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE)
1007 {
1008 return i;
1009 }
1010 }
1011
1012 return -1;
1013}
1014
daniel@transgaming.coma9571682012-11-28 19:33:08 +00001015D3DFORMAT Renderer9::ConvertTextureInternalFormat(GLint internalformat)
1016{
1017 switch (internalformat)
1018 {
1019 case GL_DEPTH_COMPONENT16:
1020 case GL_DEPTH_COMPONENT32_OES:
1021 case GL_DEPTH24_STENCIL8_OES:
1022 return D3DFMT_INTZ;
1023 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1024 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1025 return D3DFMT_DXT1;
1026 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1027 return D3DFMT_DXT3;
1028 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
1029 return D3DFMT_DXT5;
1030 case GL_RGBA32F_EXT:
1031 case GL_RGB32F_EXT:
1032 case GL_ALPHA32F_EXT:
1033 case GL_LUMINANCE32F_EXT:
1034 case GL_LUMINANCE_ALPHA32F_EXT:
1035 return D3DFMT_A32B32G32R32F;
1036 case GL_RGBA16F_EXT:
1037 case GL_RGB16F_EXT:
1038 case GL_ALPHA16F_EXT:
1039 case GL_LUMINANCE16F_EXT:
1040 case GL_LUMINANCE_ALPHA16F_EXT:
1041 return D3DFMT_A16B16G16R16F;
1042 case GL_LUMINANCE8_EXT:
1043 if (getLuminanceTextureSupport())
1044 {
1045 return D3DFMT_L8;
1046 }
1047 break;
1048 case GL_LUMINANCE8_ALPHA8_EXT:
1049 if (getLuminanceAlphaTextureSupport())
1050 {
1051 return D3DFMT_A8L8;
1052 }
1053 break;
1054 case GL_RGB8_OES:
1055 case GL_RGB565:
1056 return D3DFMT_X8R8G8B8;
1057 }
1058
1059 return D3DFMT_A8R8G8B8;
1060}
1061
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001062bool Renderer9::copyToRenderTarget(gl::TextureStorage2D *dest, gl::TextureStorage2D *source)
1063{
1064 bool result = false;
1065
1066 if (source && dest)
1067 {
1068 int levels = source->levelCount();
1069 for (int i = 0; i < levels; ++i)
1070 {
1071 IDirect3DSurface9 *srcSurf = source->getSurfaceLevel(i, false);
1072 IDirect3DSurface9 *dstSurf = dest->getSurfaceLevel(i, false);
1073
1074 result = copyToRenderTarget(dstSurf, srcSurf, source->isManaged());
1075
1076 if (srcSurf) srcSurf->Release();
1077 if (dstSurf) dstSurf->Release();
1078
1079 if (!result)
1080 return false;
1081 }
1082 }
1083
1084 return result;
1085}
1086
1087bool Renderer9::copyToRenderTarget(gl::TextureStorageCubeMap *dest, gl::TextureStorageCubeMap *source)
1088{
1089 bool result = false;
1090
1091 if (source && dest)
1092 {
1093 int levels = source->levelCount();
1094 for (int f = 0; f < 6; f++)
1095 {
1096 for (int i = 0; i < levels; i++)
1097 {
1098 IDirect3DSurface9 *srcSurf = source->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
1099 IDirect3DSurface9 *dstSurf = dest->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
1100
1101 result = copyToRenderTarget(dstSurf, srcSurf, source->isManaged());
1102
1103 if (srcSurf) srcSurf->Release();
1104 if (dstSurf) dstSurf->Release();
1105
1106 if (!result)
1107 return false;
1108 }
1109 }
1110 }
1111
1112 return result;
1113}
1114
daniel@transgaming.com2507f412012-10-31 18:46:48 +00001115D3DPOOL Renderer9::getBufferPool(DWORD usage) const
daniel@transgaming.com621ce052012-10-31 17:52:29 +00001116{
1117 if (mD3d9Ex != NULL)
1118 {
1119 return D3DPOOL_DEFAULT;
1120 }
1121 else
1122 {
1123 if (!(usage & D3DUSAGE_DYNAMIC))
1124 {
1125 return D3DPOOL_MANAGED;
1126 }
1127 }
1128
1129 return D3DPOOL_DEFAULT;
1130}
1131
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001132bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset,
1133 gl::TextureStorage2D *storage, GLint level)
1134{
1135 return mBlit->copy(framebuffer, sourceRect, destFormat, xoffset, yoffset, storage, level);
1136}
1137
1138bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset,
1139 gl::TextureStorageCubeMap *storage, GLenum target, GLint level)
1140{
1141 return mBlit->copy(framebuffer, sourceRect, destFormat, xoffset, yoffset, storage, target, level);
1142}
1143
1144bool Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
1145{
1146 return mBlit->boxFilter(source, dest);
1147}
1148
daniel@transgaming.com2507f412012-10-31 18:46:48 +00001149D3DPOOL Renderer9::getTexturePool(DWORD usage) const
daniel@transgaming.com621ce052012-10-31 17:52:29 +00001150{
1151 if (mD3d9Ex != NULL)
1152 {
1153 return D3DPOOL_DEFAULT;
1154 }
1155 else
1156 {
1157 if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)))
1158 {
1159 return D3DPOOL_MANAGED;
1160 }
1161 }
1162
1163 return D3DPOOL_DEFAULT;
1164}
1165
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001166bool Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
1167{
1168 if (source && dest)
1169 {
1170 HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
1171 IDirect3DDevice9 *device = getDevice(); // D3D9_REPLACE
1172
1173 if (fromManaged)
1174 {
1175 D3DSURFACE_DESC desc;
1176 source->GetDesc(&desc);
1177
1178 IDirect3DSurface9 *surf = 0;
1179 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
1180
1181 if (SUCCEEDED(result))
1182 {
1183 gl::Image::CopyLockableSurfaces(surf, source);
1184 result = device->UpdateSurface(surf, NULL, dest, NULL);
1185 surf->Release();
1186 }
1187 }
1188 else
1189 {
1190 endScene();
1191 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1192 }
1193
1194 if (FAILED(result))
1195 {
1196 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1197 return false;
1198 }
1199 }
1200
1201 return true;
1202}
1203
daniel@transgaming.com621ce052012-10-31 17:52:29 +00001204}