|
1 #include "precompiled.h" |
|
2 // |
|
3 // Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. |
|
4 // Use of this source code is governed by a BSD-style license that can be |
|
5 // found in the LICENSE file. |
|
6 // |
|
7 |
|
8 // Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer. |
|
9 |
|
10 #include "libGLESv2/main.h" |
|
11 #include "libGLESv2/Buffer.h" |
|
12 #include "libGLESv2/Texture.h" |
|
13 #include "libGLESv2/Framebuffer.h" |
|
14 #include "libGLESv2/Renderbuffer.h" |
|
15 #include "libGLESv2/ProgramBinary.h" |
|
16 #include "libGLESv2/renderer/IndexDataManager.h" |
|
17 #include "libGLESv2/renderer/Renderer9.h" |
|
18 #include "libGLESv2/renderer/renderer9_utils.h" |
|
19 #include "libGLESv2/renderer/ShaderExecutable9.h" |
|
20 #include "libGLESv2/renderer/SwapChain9.h" |
|
21 #include "libGLESv2/renderer/TextureStorage9.h" |
|
22 #include "libGLESv2/renderer/Image9.h" |
|
23 #include "libGLESv2/renderer/Blit.h" |
|
24 #include "libGLESv2/renderer/RenderTarget9.h" |
|
25 #include "libGLESv2/renderer/VertexBuffer9.h" |
|
26 #include "libGLESv2/renderer/IndexBuffer9.h" |
|
27 #include "libGLESv2/renderer/BufferStorage9.h" |
|
28 #include "libGLESv2/renderer/Query9.h" |
|
29 #include "libGLESv2/renderer/Fence9.h" |
|
30 |
|
31 #include "libEGL/Display.h" |
|
32 |
|
33 // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros |
|
34 #define REF_RAST 0 |
|
35 |
|
36 // The "Debug This Pixel..." feature in PIX often fails when using the |
|
37 // D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7 |
|
38 // machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file. |
|
39 #if !defined(ANGLE_ENABLE_D3D9EX) |
|
40 // Enables use of the IDirect3D9Ex interface, when available |
|
41 #define ANGLE_ENABLE_D3D9EX 1 |
|
42 #endif // !defined(ANGLE_ENABLE_D3D9EX) |
|
43 |
|
44 namespace rx |
|
45 { |
|
46 static const D3DFORMAT RenderTargetFormats[] = |
|
47 { |
|
48 D3DFMT_A1R5G5B5, |
|
49 // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value. |
|
50 D3DFMT_A8R8G8B8, |
|
51 D3DFMT_R5G6B5, |
|
52 // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format |
|
53 D3DFMT_X8R8G8B8 |
|
54 }; |
|
55 |
|
56 static const D3DFORMAT DepthStencilFormats[] = |
|
57 { |
|
58 D3DFMT_UNKNOWN, |
|
59 // D3DFMT_D16_LOCKABLE, |
|
60 D3DFMT_D32, |
|
61 // D3DFMT_D15S1, |
|
62 D3DFMT_D24S8, |
|
63 D3DFMT_D24X8, |
|
64 // D3DFMT_D24X4S4, |
|
65 D3DFMT_D16, |
|
66 // D3DFMT_D32F_LOCKABLE, |
|
67 // D3DFMT_D24FS8 |
|
68 }; |
|
69 |
|
70 enum |
|
71 { |
|
72 MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256, |
|
73 MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32, |
|
74 MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224, |
|
75 MAX_VARYING_VECTORS_SM2 = 8, |
|
76 MAX_VARYING_VECTORS_SM3 = 10, |
|
77 |
|
78 MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4 |
|
79 }; |
|
80 |
|
81 Renderer9::Renderer9(egl::Display *display, HDC hDc, bool softwareDevice) : Renderer(display), mDc(hDc), mSoftwareDevice(softwareDevice) |
|
82 { |
|
83 mD3d9Module = NULL; |
|
84 |
|
85 mD3d9 = NULL; |
|
86 mD3d9Ex = NULL; |
|
87 mDevice = NULL; |
|
88 mDeviceEx = NULL; |
|
89 mDeviceWindow = NULL; |
|
90 mBlit = NULL; |
|
91 |
|
92 mAdapter = D3DADAPTER_DEFAULT; |
|
93 |
|
94 #if REF_RAST == 1 || defined(FORCE_REF_RAST) |
|
95 mDeviceType = D3DDEVTYPE_REF; |
|
96 #else |
|
97 mDeviceType = D3DDEVTYPE_HAL; |
|
98 #endif |
|
99 |
|
100 mDeviceLost = false; |
|
101 |
|
102 mMaxSupportedSamples = 0; |
|
103 |
|
104 mMaskedClearSavedState = NULL; |
|
105 |
|
106 mVertexDataManager = NULL; |
|
107 mIndexDataManager = NULL; |
|
108 mLineLoopIB = NULL; |
|
109 |
|
110 mMaxNullColorbufferLRU = 0; |
|
111 for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) |
|
112 { |
|
113 mNullColorbufferCache[i].lruCount = 0; |
|
114 mNullColorbufferCache[i].width = 0; |
|
115 mNullColorbufferCache[i].height = 0; |
|
116 mNullColorbufferCache[i].buffer = NULL; |
|
117 } |
|
118 } |
|
119 |
|
120 Renderer9::~Renderer9() |
|
121 { |
|
122 releaseDeviceResources(); |
|
123 |
|
124 if (mDevice) |
|
125 { |
|
126 // If the device is lost, reset it first to prevent leaving the driver in an unstable state |
|
127 if (testDeviceLost(false)) |
|
128 { |
|
129 resetDevice(); |
|
130 } |
|
131 |
|
132 mDevice->Release(); |
|
133 mDevice = NULL; |
|
134 } |
|
135 |
|
136 if (mDeviceEx) |
|
137 { |
|
138 mDeviceEx->Release(); |
|
139 mDeviceEx = NULL; |
|
140 } |
|
141 |
|
142 if (mD3d9) |
|
143 { |
|
144 mD3d9->Release(); |
|
145 mD3d9 = NULL; |
|
146 } |
|
147 |
|
148 if (mDeviceWindow) |
|
149 { |
|
150 DestroyWindow(mDeviceWindow); |
|
151 mDeviceWindow = NULL; |
|
152 } |
|
153 |
|
154 if (mD3d9Ex) |
|
155 { |
|
156 mD3d9Ex->Release(); |
|
157 mD3d9Ex = NULL; |
|
158 } |
|
159 |
|
160 if (mD3d9Module) |
|
161 { |
|
162 mD3d9Module = NULL; |
|
163 } |
|
164 |
|
165 while (!mMultiSampleSupport.empty()) |
|
166 { |
|
167 delete [] mMultiSampleSupport.begin()->second; |
|
168 mMultiSampleSupport.erase(mMultiSampleSupport.begin()); |
|
169 } |
|
170 } |
|
171 |
|
172 Renderer9 *Renderer9::makeRenderer9(Renderer *renderer) |
|
173 { |
|
174 ASSERT(HAS_DYNAMIC_TYPE(rx::Renderer9*, renderer)); |
|
175 return static_cast<rx::Renderer9*>(renderer); |
|
176 } |
|
177 |
|
178 EGLint Renderer9::initialize() |
|
179 { |
|
180 if (!initializeCompiler()) |
|
181 { |
|
182 return EGL_NOT_INITIALIZED; |
|
183 } |
|
184 |
|
185 if (mSoftwareDevice) |
|
186 { |
|
187 mD3d9Module = GetModuleHandle(TEXT("swiftshader_d3d9.dll")); |
|
188 } |
|
189 else |
|
190 { |
|
191 mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); |
|
192 } |
|
193 |
|
194 if (mD3d9Module == NULL) |
|
195 { |
|
196 ERR("No D3D9 module found - aborting!\n"); |
|
197 return EGL_NOT_INITIALIZED; |
|
198 } |
|
199 |
|
200 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); |
|
201 Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); |
|
202 |
|
203 // Use Direct3D9Ex if available. Among other things, this version is less |
|
204 // inclined to report a lost context, for example when the user switches |
|
205 // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available. |
|
206 if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) |
|
207 { |
|
208 ASSERT(mD3d9Ex); |
|
209 mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9)); |
|
210 ASSERT(mD3d9); |
|
211 } |
|
212 else |
|
213 { |
|
214 mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); |
|
215 } |
|
216 |
|
217 if (!mD3d9) |
|
218 { |
|
219 ERR("Could not create D3D9 device - aborting!\n"); |
|
220 return EGL_NOT_INITIALIZED; |
|
221 } |
|
222 |
|
223 if (mDc != NULL) |
|
224 { |
|
225 // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to |
|
226 } |
|
227 |
|
228 HRESULT result; |
|
229 |
|
230 // Give up on getting device caps after about one second. |
|
231 for (int i = 0; i < 10; ++i) |
|
232 { |
|
233 result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); |
|
234 if (SUCCEEDED(result)) |
|
235 { |
|
236 break; |
|
237 } |
|
238 else if (result == D3DERR_NOTAVAILABLE) |
|
239 { |
|
240 Sleep(100); // Give the driver some time to initialize/recover |
|
241 } |
|
242 else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from |
|
243 { |
|
244 ERR("failed to get device caps (0x%x)\n", result); |
|
245 return EGL_NOT_INITIALIZED; |
|
246 } |
|
247 } |
|
248 |
|
249 if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0)) |
|
250 { |
|
251 ERR("Renderer does not support PS 2.0. aborting!\n"); |
|
252 return EGL_NOT_INITIALIZED; |
|
253 } |
|
254 |
|
255 // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported. |
|
256 // This is required by Texture2D::convertToRenderTarget. |
|
257 if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) |
|
258 { |
|
259 ERR("Renderer does not support stretctrect from textures!\n"); |
|
260 return EGL_NOT_INITIALIZED; |
|
261 } |
|
262 |
|
263 mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); |
|
264 |
|
265 // ATI cards on XP have problems with non-power-of-two textures. |
|
266 mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && |
|
267 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && |
|
268 !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && |
|
269 !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD); |
|
270 |
|
271 // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec |
|
272 mSupportsTextureFilterAnisotropy = ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2)); |
|
273 |
|
274 mMinSwapInterval = 4; |
|
275 mMaxSwapInterval = 0; |
|
276 |
|
277 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) |
|
278 { |
|
279 mMinSwapInterval = std::min(mMinSwapInterval, 0); |
|
280 mMaxSwapInterval = std::max(mMaxSwapInterval, 0); |
|
281 } |
|
282 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) |
|
283 { |
|
284 mMinSwapInterval = std::min(mMinSwapInterval, 1); |
|
285 mMaxSwapInterval = std::max(mMaxSwapInterval, 1); |
|
286 } |
|
287 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) |
|
288 { |
|
289 mMinSwapInterval = std::min(mMinSwapInterval, 2); |
|
290 mMaxSwapInterval = std::max(mMaxSwapInterval, 2); |
|
291 } |
|
292 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) |
|
293 { |
|
294 mMinSwapInterval = std::min(mMinSwapInterval, 3); |
|
295 mMaxSwapInterval = std::max(mMaxSwapInterval, 3); |
|
296 } |
|
297 if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) |
|
298 { |
|
299 mMinSwapInterval = std::min(mMinSwapInterval, 4); |
|
300 mMaxSwapInterval = std::max(mMaxSwapInterval, 4); |
|
301 } |
|
302 |
|
303 int max = 0; |
|
304 for (unsigned int i = 0; i < ArraySize(RenderTargetFormats); ++i) |
|
305 { |
|
306 bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1]; |
|
307 getMultiSampleSupport(RenderTargetFormats[i], multisampleArray); |
|
308 mMultiSampleSupport[RenderTargetFormats[i]] = multisampleArray; |
|
309 |
|
310 for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j) |
|
311 { |
|
312 if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max) |
|
313 { |
|
314 max = j; |
|
315 } |
|
316 } |
|
317 } |
|
318 |
|
319 for (unsigned int i = 0; i < ArraySize(DepthStencilFormats); ++i) |
|
320 { |
|
321 if (DepthStencilFormats[i] == D3DFMT_UNKNOWN) |
|
322 continue; |
|
323 |
|
324 bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1]; |
|
325 getMultiSampleSupport(DepthStencilFormats[i], multisampleArray); |
|
326 mMultiSampleSupport[DepthStencilFormats[i]] = multisampleArray; |
|
327 |
|
328 for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j) |
|
329 { |
|
330 if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max) |
|
331 { |
|
332 max = j; |
|
333 } |
|
334 } |
|
335 } |
|
336 |
|
337 mMaxSupportedSamples = max; |
|
338 |
|
339 static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); |
|
340 static const TCHAR className[] = TEXT("STATIC"); |
|
341 |
|
342 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL); |
|
343 |
|
344 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); |
|
345 DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; |
|
346 |
|
347 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); |
|
348 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) |
|
349 { |
|
350 return EGL_BAD_ALLOC; |
|
351 } |
|
352 |
|
353 if (FAILED(result)) |
|
354 { |
|
355 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); |
|
356 |
|
357 if (FAILED(result)) |
|
358 { |
|
359 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); |
|
360 return EGL_BAD_ALLOC; |
|
361 } |
|
362 } |
|
363 |
|
364 if (mD3d9Ex) |
|
365 { |
|
366 result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx); |
|
367 ASSERT(SUCCEEDED(result)); |
|
368 } |
|
369 |
|
370 mVertexShaderCache.initialize(mDevice); |
|
371 mPixelShaderCache.initialize(mDevice); |
|
372 |
|
373 // Check occlusion query support |
|
374 IDirect3DQuery9 *occlusionQuery = NULL; |
|
375 if (SUCCEEDED(mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery) |
|
376 { |
|
377 occlusionQuery->Release(); |
|
378 mOcclusionQuerySupport = true; |
|
379 } |
|
380 else |
|
381 { |
|
382 mOcclusionQuerySupport = false; |
|
383 } |
|
384 |
|
385 // Check event query support |
|
386 IDirect3DQuery9 *eventQuery = NULL; |
|
387 if (SUCCEEDED(mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery) |
|
388 { |
|
389 eventQuery->Release(); |
|
390 mEventQuerySupport = true; |
|
391 } |
|
392 else |
|
393 { |
|
394 mEventQuerySupport = false; |
|
395 } |
|
396 |
|
397 D3DDISPLAYMODE currentDisplayMode; |
|
398 mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); |
|
399 |
|
400 // Check vertex texture support |
|
401 // Only Direct3D 10 ready devices support all the necessary vertex texture formats. |
|
402 // We test this using D3D9 by checking support for the R16F format. |
|
403 mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) && |
|
404 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, |
|
405 D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); |
|
406 |
|
407 // Check depth texture support |
|
408 // we use INTZ for depth textures in Direct3D9 |
|
409 // we also want NULL texture support to ensure the we can make depth-only FBOs |
|
410 // see http://aras-p.info/texts/D3D9GPUHacks.html |
|
411 mDepthTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, |
|
412 D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ)) && |
|
413 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, |
|
414 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL)); |
|
415 |
|
416 // Check 32 bit floating point texture support |
|
417 mFloat32FilterSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, |
|
418 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && |
|
419 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, |
|
420 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); |
|
421 |
|
422 mFloat32RenderSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, |
|
423 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && |
|
424 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, |
|
425 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); |
|
426 |
|
427 if (!mFloat32FilterSupport && !mFloat32RenderSupport) |
|
428 { |
|
429 mFloat32TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, |
|
430 D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && |
|
431 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, |
|
432 D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); |
|
433 } |
|
434 else |
|
435 { |
|
436 mFloat32TextureSupport = true; |
|
437 } |
|
438 |
|
439 // Check 16 bit floating point texture support |
|
440 mFloat16FilterSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, |
|
441 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && |
|
442 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, |
|
443 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); |
|
444 |
|
445 mFloat16RenderSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, |
|
446 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && |
|
447 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, |
|
448 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); |
|
449 |
|
450 if (!mFloat16FilterSupport && !mFloat16RenderSupport) |
|
451 { |
|
452 mFloat16TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, |
|
453 D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && |
|
454 SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, |
|
455 D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); |
|
456 } |
|
457 else |
|
458 { |
|
459 mFloat16TextureSupport = true; |
|
460 } |
|
461 |
|
462 // Check DXT texture support |
|
463 mDXT1TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1)); |
|
464 mDXT3TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3)); |
|
465 mDXT5TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5)); |
|
466 |
|
467 // Check luminance[alpha] texture support |
|
468 mLuminanceTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8)); |
|
469 mLuminanceAlphaTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8)); |
|
470 |
|
471 initializeDevice(); |
|
472 |
|
473 return EGL_SUCCESS; |
|
474 } |
|
475 |
|
476 // do any one-time device initialization |
|
477 // NOTE: this is also needed after a device lost/reset |
|
478 // to reset the scene status and ensure the default states are reset. |
|
479 void Renderer9::initializeDevice() |
|
480 { |
|
481 // Permanent non-default states |
|
482 mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); |
|
483 mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE); |
|
484 |
|
485 if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) |
|
486 { |
|
487 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize); |
|
488 } |
|
489 else |
|
490 { |
|
491 mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f |
|
492 } |
|
493 |
|
494 markAllStateDirty(); |
|
495 |
|
496 mSceneStarted = false; |
|
497 |
|
498 ASSERT(!mBlit && !mVertexDataManager && !mIndexDataManager); |
|
499 mBlit = new Blit(this); |
|
500 mVertexDataManager = new rx::VertexDataManager(this); |
|
501 mIndexDataManager = new rx::IndexDataManager(this); |
|
502 } |
|
503 |
|
504 D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters() |
|
505 { |
|
506 D3DPRESENT_PARAMETERS presentParameters = {0}; |
|
507 |
|
508 // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters. |
|
509 presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; |
|
510 presentParameters.BackBufferCount = 1; |
|
511 presentParameters.BackBufferFormat = D3DFMT_UNKNOWN; |
|
512 presentParameters.BackBufferWidth = 1; |
|
513 presentParameters.BackBufferHeight = 1; |
|
514 presentParameters.EnableAutoDepthStencil = FALSE; |
|
515 presentParameters.Flags = 0; |
|
516 presentParameters.hDeviceWindow = mDeviceWindow; |
|
517 presentParameters.MultiSampleQuality = 0; |
|
518 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; |
|
519 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; |
|
520 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; |
|
521 presentParameters.Windowed = TRUE; |
|
522 |
|
523 return presentParameters; |
|
524 } |
|
525 |
|
526 int Renderer9::generateConfigs(ConfigDesc **configDescList) |
|
527 { |
|
528 D3DDISPLAYMODE currentDisplayMode; |
|
529 mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); |
|
530 |
|
531 unsigned int numRenderFormats = ArraySize(RenderTargetFormats); |
|
532 unsigned int numDepthFormats = ArraySize(DepthStencilFormats); |
|
533 (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats]; |
|
534 int numConfigs = 0; |
|
535 |
|
536 for (unsigned int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++) |
|
537 { |
|
538 D3DFORMAT renderTargetFormat = RenderTargetFormats[formatIndex]; |
|
539 |
|
540 HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat); |
|
541 |
|
542 if (SUCCEEDED(result)) |
|
543 { |
|
544 for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++) |
|
545 { |
|
546 D3DFORMAT depthStencilFormat = DepthStencilFormats[depthStencilIndex]; |
|
547 HRESULT result = D3D_OK; |
|
548 |
|
549 if(depthStencilFormat != D3DFMT_UNKNOWN) |
|
550 { |
|
551 result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat); |
|
552 } |
|
553 |
|
554 if (SUCCEEDED(result)) |
|
555 { |
|
556 if(depthStencilFormat != D3DFMT_UNKNOWN) |
|
557 { |
|
558 result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat); |
|
559 } |
|
560 |
|
561 if (SUCCEEDED(result)) |
|
562 { |
|
563 ConfigDesc newConfig; |
|
564 newConfig.renderTargetFormat = d3d9_gl::ConvertBackBufferFormat(renderTargetFormat); |
|
565 newConfig.depthStencilFormat = d3d9_gl::ConvertDepthStencilFormat(depthStencilFormat); |
|
566 newConfig.multiSample = 0; // FIXME: enumerate multi-sampling |
|
567 newConfig.fastConfig = (currentDisplayMode.Format == renderTargetFormat); |
|
568 |
|
569 (*configDescList)[numConfigs++] = newConfig; |
|
570 } |
|
571 } |
|
572 } |
|
573 } |
|
574 } |
|
575 |
|
576 return numConfigs; |
|
577 } |
|
578 |
|
579 void Renderer9::deleteConfigs(ConfigDesc *configDescList) |
|
580 { |
|
581 delete [] (configDescList); |
|
582 } |
|
583 |
|
584 void Renderer9::startScene() |
|
585 { |
|
586 if (!mSceneStarted) |
|
587 { |
|
588 long result = mDevice->BeginScene(); |
|
589 if (SUCCEEDED(result)) { |
|
590 // This is defensive checking against the device being |
|
591 // lost at unexpected times. |
|
592 mSceneStarted = true; |
|
593 } |
|
594 } |
|
595 } |
|
596 |
|
597 void Renderer9::endScene() |
|
598 { |
|
599 if (mSceneStarted) |
|
600 { |
|
601 // EndScene can fail if the device was lost, for example due |
|
602 // to a TDR during a draw call. |
|
603 mDevice->EndScene(); |
|
604 mSceneStarted = false; |
|
605 } |
|
606 } |
|
607 |
|
608 void Renderer9::sync(bool block) |
|
609 { |
|
610 HRESULT result; |
|
611 |
|
612 IDirect3DQuery9* query = allocateEventQuery(); |
|
613 if (!query) |
|
614 { |
|
615 return; |
|
616 } |
|
617 |
|
618 result = query->Issue(D3DISSUE_END); |
|
619 ASSERT(SUCCEEDED(result)); |
|
620 |
|
621 do |
|
622 { |
|
623 result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); |
|
624 |
|
625 if(block && result == S_FALSE) |
|
626 { |
|
627 // Keep polling, but allow other threads to do something useful first |
|
628 Sleep(0); |
|
629 // explicitly check for device loss |
|
630 // some drivers seem to return S_FALSE even if the device is lost |
|
631 // instead of D3DERR_DEVICELOST like they should |
|
632 if (testDeviceLost(false)) |
|
633 { |
|
634 result = D3DERR_DEVICELOST; |
|
635 } |
|
636 } |
|
637 } |
|
638 while(block && result == S_FALSE); |
|
639 |
|
640 freeEventQuery(query); |
|
641 |
|
642 if (d3d9::isDeviceLostError(result)) |
|
643 { |
|
644 notifyDeviceLost(); |
|
645 } |
|
646 } |
|
647 |
|
648 SwapChain *Renderer9::createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) |
|
649 { |
|
650 return new rx::SwapChain9(this, window, shareHandle, backBufferFormat, depthBufferFormat); |
|
651 } |
|
652 |
|
653 IDirect3DQuery9* Renderer9::allocateEventQuery() |
|
654 { |
|
655 IDirect3DQuery9 *query = NULL; |
|
656 |
|
657 if (mEventQueryPool.empty()) |
|
658 { |
|
659 HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query); |
|
660 ASSERT(SUCCEEDED(result)); |
|
661 } |
|
662 else |
|
663 { |
|
664 query = mEventQueryPool.back(); |
|
665 mEventQueryPool.pop_back(); |
|
666 } |
|
667 |
|
668 return query; |
|
669 } |
|
670 |
|
671 void Renderer9::freeEventQuery(IDirect3DQuery9* query) |
|
672 { |
|
673 if (mEventQueryPool.size() > 1000) |
|
674 { |
|
675 query->Release(); |
|
676 } |
|
677 else |
|
678 { |
|
679 mEventQueryPool.push_back(query); |
|
680 } |
|
681 } |
|
682 |
|
683 IDirect3DVertexShader9 *Renderer9::createVertexShader(const DWORD *function, size_t length) |
|
684 { |
|
685 return mVertexShaderCache.create(function, length); |
|
686 } |
|
687 |
|
688 IDirect3DPixelShader9 *Renderer9::createPixelShader(const DWORD *function, size_t length) |
|
689 { |
|
690 return mPixelShaderCache.create(function, length); |
|
691 } |
|
692 |
|
693 HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer) |
|
694 { |
|
695 D3DPOOL Pool = getBufferPool(Usage); |
|
696 return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL); |
|
697 } |
|
698 |
|
699 VertexBuffer *Renderer9::createVertexBuffer() |
|
700 { |
|
701 return new VertexBuffer9(this); |
|
702 } |
|
703 |
|
704 HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer) |
|
705 { |
|
706 D3DPOOL Pool = getBufferPool(Usage); |
|
707 return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL); |
|
708 } |
|
709 |
|
710 IndexBuffer *Renderer9::createIndexBuffer() |
|
711 { |
|
712 return new IndexBuffer9(this); |
|
713 } |
|
714 |
|
715 BufferStorage *Renderer9::createBufferStorage() |
|
716 { |
|
717 return new BufferStorage9(); |
|
718 } |
|
719 |
|
720 QueryImpl *Renderer9::createQuery(GLenum type) |
|
721 { |
|
722 return new Query9(this, type); |
|
723 } |
|
724 |
|
725 FenceImpl *Renderer9::createFence() |
|
726 { |
|
727 return new Fence9(this); |
|
728 } |
|
729 |
|
730 void Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) |
|
731 { |
|
732 bool *forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; |
|
733 gl::SamplerState *appliedSamplers = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates: mCurVertexSamplerStates; |
|
734 |
|
735 if (forceSetSamplers[index] || memcmp(&samplerState, &appliedSamplers[index], sizeof(gl::SamplerState)) != 0) |
|
736 { |
|
737 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; |
|
738 int d3dSampler = index + d3dSamplerOffset; |
|
739 |
|
740 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS)); |
|
741 mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT)); |
|
742 |
|
743 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy)); |
|
744 D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; |
|
745 gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy); |
|
746 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); |
|
747 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); |
|
748 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.lodOffset); |
|
749 if (mSupportsTextureFilterAnisotropy) |
|
750 { |
|
751 mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); |
|
752 } |
|
753 } |
|
754 |
|
755 forceSetSamplers[index] = false; |
|
756 appliedSamplers[index] = samplerState; |
|
757 } |
|
758 |
|
759 void Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture) |
|
760 { |
|
761 int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; |
|
762 int d3dSampler = index + d3dSamplerOffset; |
|
763 IDirect3DBaseTexture9 *d3dTexture = NULL; |
|
764 unsigned int serial = 0; |
|
765 bool forceSetTexture = false; |
|
766 |
|
767 unsigned int *appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials; |
|
768 |
|
769 if (texture) |
|
770 { |
|
771 TextureStorageInterface *texStorage = texture->getNativeTexture(); |
|
772 if (texStorage) |
|
773 { |
|
774 TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage->getStorageInstance()); |
|
775 d3dTexture = storage9->getBaseTexture(); |
|
776 } |
|
777 // If we get NULL back from getBaseTexture here, something went wrong |
|
778 // in the texture class and we're unexpectedly missing the d3d texture |
|
779 ASSERT(d3dTexture != NULL); |
|
780 |
|
781 serial = texture->getTextureSerial(); |
|
782 forceSetTexture = texture->hasDirtyImages(); |
|
783 } |
|
784 |
|
785 if (forceSetTexture || appliedSerials[index] != serial) |
|
786 { |
|
787 mDevice->SetTexture(d3dSampler, d3dTexture); |
|
788 } |
|
789 |
|
790 appliedSerials[index] = serial; |
|
791 } |
|
792 |
|
793 void Renderer9::setRasterizerState(const gl::RasterizerState &rasterState) |
|
794 { |
|
795 bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0; |
|
796 |
|
797 if (rasterStateChanged) |
|
798 { |
|
799 // Set the cull mode |
|
800 if (rasterState.cullFace) |
|
801 { |
|
802 mDevice->SetRenderState(D3DRS_CULLMODE, gl_d3d9::ConvertCullMode(rasterState.cullMode, rasterState.frontFace)); |
|
803 } |
|
804 else |
|
805 { |
|
806 mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); |
|
807 } |
|
808 |
|
809 if (rasterState.polygonOffsetFill) |
|
810 { |
|
811 if (mCurDepthSize > 0) |
|
812 { |
|
813 mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&rasterState.polygonOffsetFactor); |
|
814 |
|
815 float depthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(mCurDepthSize)); |
|
816 mDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&depthBias); |
|
817 } |
|
818 } |
|
819 else |
|
820 { |
|
821 mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); |
|
822 mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); |
|
823 } |
|
824 |
|
825 mCurRasterState = rasterState; |
|
826 } |
|
827 |
|
828 mForceSetRasterState = false; |
|
829 } |
|
830 |
|
831 void Renderer9::setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor, unsigned int sampleMask) |
|
832 { |
|
833 bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0; |
|
834 bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::Color)) != 0; |
|
835 bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask; |
|
836 |
|
837 if (blendStateChanged || blendColorChanged) |
|
838 { |
|
839 if (blendState.blend) |
|
840 { |
|
841 mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); |
|
842 |
|
843 if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && |
|
844 blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) |
|
845 { |
|
846 mDevice->SetRenderState(D3DRS_BLENDFACTOR, gl_d3d9::ConvertColor(blendColor)); |
|
847 } |
|
848 else |
|
849 { |
|
850 mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha), |
|
851 gl::unorm<8>(blendColor.alpha), |
|
852 gl::unorm<8>(blendColor.alpha), |
|
853 gl::unorm<8>(blendColor.alpha))); |
|
854 } |
|
855 |
|
856 mDevice->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB)); |
|
857 mDevice->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB)); |
|
858 mDevice->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB)); |
|
859 |
|
860 if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha || |
|
861 blendState.destBlendRGB != blendState.destBlendAlpha || |
|
862 blendState.blendEquationRGB != blendState.blendEquationAlpha) |
|
863 { |
|
864 mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); |
|
865 |
|
866 mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha)); |
|
867 mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha)); |
|
868 mDevice->SetRenderState(D3DRS_BLENDOPALPHA, gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha)); |
|
869 } |
|
870 else |
|
871 { |
|
872 mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); |
|
873 } |
|
874 } |
|
875 else |
|
876 { |
|
877 mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); |
|
878 } |
|
879 |
|
880 if (blendState.sampleAlphaToCoverage) |
|
881 { |
|
882 FIXME("Sample alpha to coverage is unimplemented."); |
|
883 } |
|
884 |
|
885 // Set the color mask |
|
886 bool zeroColorMaskAllowed = getAdapterVendor() != VENDOR_ID_AMD; |
|
887 // Apparently some ATI cards have a bug where a draw with a zero color |
|
888 // write mask can cause later draws to have incorrect results. Instead, |
|
889 // set a nonzero color write mask but modify the blend state so that no |
|
890 // drawing is done. |
|
891 // http://code.google.com/p/angleproject/issues/detail?id=169 |
|
892 |
|
893 DWORD colorMask = gl_d3d9::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen, |
|
894 blendState.colorMaskBlue, blendState.colorMaskAlpha); |
|
895 if (colorMask == 0 && !zeroColorMaskAllowed) |
|
896 { |
|
897 // Enable green channel, but set blending so nothing will be drawn. |
|
898 mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN); |
|
899 mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); |
|
900 |
|
901 mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); |
|
902 mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); |
|
903 mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); |
|
904 } |
|
905 else |
|
906 { |
|
907 mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask); |
|
908 } |
|
909 |
|
910 mDevice->SetRenderState(D3DRS_DITHERENABLE, blendState.dither ? TRUE : FALSE); |
|
911 |
|
912 mCurBlendState = blendState; |
|
913 mCurBlendColor = blendColor; |
|
914 } |
|
915 |
|
916 if (sampleMaskChanged) |
|
917 { |
|
918 // Set the multisample mask |
|
919 mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); |
|
920 mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask)); |
|
921 |
|
922 mCurSampleMask = sampleMask; |
|
923 } |
|
924 |
|
925 mForceSetBlendState = false; |
|
926 } |
|
927 |
|
928 void Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, |
|
929 int stencilBackRef, bool frontFaceCCW) |
|
930 { |
|
931 bool depthStencilStateChanged = mForceSetDepthStencilState || |
|
932 memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0; |
|
933 bool stencilRefChanged = mForceSetDepthStencilState || stencilRef != mCurStencilRef || |
|
934 stencilBackRef != mCurStencilBackRef; |
|
935 bool frontFaceCCWChanged = mForceSetDepthStencilState || frontFaceCCW != mCurFrontFaceCCW; |
|
936 |
|
937 if (depthStencilStateChanged) |
|
938 { |
|
939 if (depthStencilState.depthTest) |
|
940 { |
|
941 mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); |
|
942 mDevice->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthStencilState.depthFunc)); |
|
943 } |
|
944 else |
|
945 { |
|
946 mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); |
|
947 } |
|
948 |
|
949 mCurDepthStencilState = depthStencilState; |
|
950 } |
|
951 |
|
952 if (depthStencilStateChanged || stencilRefChanged || frontFaceCCWChanged) |
|
953 { |
|
954 if (depthStencilState.stencilTest && mCurStencilSize > 0) |
|
955 { |
|
956 mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); |
|
957 mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); |
|
958 |
|
959 // FIXME: Unsupported by D3D9 |
|
960 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; |
|
961 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK; |
|
962 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK; |
|
963 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask || |
|
964 stencilRef != stencilBackRef || |
|
965 depthStencilState.stencilMask != depthStencilState.stencilBackMask) |
|
966 { |
|
967 ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL."); |
|
968 return gl::error(GL_INVALID_OPERATION); |
|
969 } |
|
970 |
|
971 // get the maximum size of the stencil ref |
|
972 unsigned int maxStencil = (1 << mCurStencilSize) - 1; |
|
973 |
|
974 mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, |
|
975 depthStencilState.stencilWritemask); |
|
976 mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, |
|
977 gl_d3d9::ConvertComparison(depthStencilState.stencilFunc)); |
|
978 |
|
979 mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, |
|
980 (stencilRef < (int)maxStencil) ? stencilRef : maxStencil); |
|
981 mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, |
|
982 depthStencilState.stencilMask); |
|
983 |
|
984 mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, |
|
985 gl_d3d9::ConvertStencilOp(depthStencilState.stencilFail)); |
|
986 mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, |
|
987 gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthFail)); |
|
988 mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, |
|
989 gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthPass)); |
|
990 |
|
991 mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, |
|
992 depthStencilState.stencilBackWritemask); |
|
993 mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, |
|
994 gl_d3d9::ConvertComparison(depthStencilState.stencilBackFunc)); |
|
995 |
|
996 mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, |
|
997 (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil); |
|
998 mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, |
|
999 depthStencilState.stencilBackMask); |
|
1000 |
|
1001 mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, |
|
1002 gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackFail)); |
|
1003 mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, |
|
1004 gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthFail)); |
|
1005 mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, |
|
1006 gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthPass)); |
|
1007 } |
|
1008 else |
|
1009 { |
|
1010 mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); |
|
1011 } |
|
1012 |
|
1013 mDevice->SetRenderState(D3DRS_ZWRITEENABLE, depthStencilState.depthMask ? TRUE : FALSE); |
|
1014 |
|
1015 mCurStencilRef = stencilRef; |
|
1016 mCurStencilBackRef = stencilBackRef; |
|
1017 mCurFrontFaceCCW = frontFaceCCW; |
|
1018 } |
|
1019 |
|
1020 mForceSetDepthStencilState = false; |
|
1021 } |
|
1022 |
|
1023 void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) |
|
1024 { |
|
1025 bool scissorChanged = mForceSetScissor || |
|
1026 memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || |
|
1027 enabled != mScissorEnabled; |
|
1028 |
|
1029 if (scissorChanged) |
|
1030 { |
|
1031 if (enabled) |
|
1032 { |
|
1033 RECT rect; |
|
1034 rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetDesc.width)); |
|
1035 rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetDesc.height)); |
|
1036 rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetDesc.width)); |
|
1037 rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetDesc.height)); |
|
1038 mDevice->SetScissorRect(&rect); |
|
1039 } |
|
1040 |
|
1041 mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, enabled ? TRUE : FALSE); |
|
1042 |
|
1043 mScissorEnabled = enabled; |
|
1044 mCurScissor = scissor; |
|
1045 } |
|
1046 |
|
1047 mForceSetScissor = false; |
|
1048 } |
|
1049 |
|
1050 bool Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, |
|
1051 bool ignoreViewport) |
|
1052 { |
|
1053 gl::Rectangle actualViewport = viewport; |
|
1054 float actualZNear = gl::clamp01(zNear); |
|
1055 float actualZFar = gl::clamp01(zFar); |
|
1056 if (ignoreViewport) |
|
1057 { |
|
1058 actualViewport.x = 0; |
|
1059 actualViewport.y = 0; |
|
1060 actualViewport.width = mRenderTargetDesc.width; |
|
1061 actualViewport.height = mRenderTargetDesc.height; |
|
1062 actualZNear = 0.0f; |
|
1063 actualZFar = 1.0f; |
|
1064 } |
|
1065 |
|
1066 D3DVIEWPORT9 dxViewport; |
|
1067 dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetDesc.width)); |
|
1068 dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetDesc.height)); |
|
1069 dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast<int>(mRenderTargetDesc.width) - static_cast<int>(dxViewport.X)); |
|
1070 dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast<int>(mRenderTargetDesc.height) - static_cast<int>(dxViewport.Y)); |
|
1071 dxViewport.MinZ = actualZNear; |
|
1072 dxViewport.MaxZ = actualZFar; |
|
1073 |
|
1074 if (dxViewport.Width <= 0 || dxViewport.Height <= 0) |
|
1075 { |
|
1076 return false; // Nothing to render |
|
1077 } |
|
1078 |
|
1079 bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || |
|
1080 actualZNear != mCurNear || actualZFar != mCurFar; |
|
1081 if (viewportChanged) |
|
1082 { |
|
1083 mDevice->SetViewport(&dxViewport); |
|
1084 |
|
1085 mCurViewport = actualViewport; |
|
1086 mCurNear = actualZNear; |
|
1087 mCurFar = actualZFar; |
|
1088 |
|
1089 dx_VertexConstants vc = {0}; |
|
1090 dx_PixelConstants pc = {0}; |
|
1091 |
|
1092 vc.viewAdjust[0] = (float)((actualViewport.width - (int)dxViewport.Width) + 2 * (actualViewport.x - (int)dxViewport.X) - 1) / dxViewport.Width; |
|
1093 vc.viewAdjust[1] = (float)((actualViewport.height - (int)dxViewport.Height) + 2 * (actualViewport.y - (int)dxViewport.Y) - 1) / dxViewport.Height; |
|
1094 vc.viewAdjust[2] = (float)actualViewport.width / dxViewport.Width; |
|
1095 vc.viewAdjust[3] = (float)actualViewport.height / dxViewport.Height; |
|
1096 |
|
1097 pc.viewCoords[0] = actualViewport.width * 0.5f; |
|
1098 pc.viewCoords[1] = actualViewport.height * 0.5f; |
|
1099 pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); |
|
1100 pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); |
|
1101 |
|
1102 pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f; |
|
1103 pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f; |
|
1104 pc.depthFront[2] = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f);; |
|
1105 |
|
1106 vc.depthRange[0] = actualZNear; |
|
1107 vc.depthRange[1] = actualZFar; |
|
1108 vc.depthRange[2] = actualZFar - actualZNear; |
|
1109 |
|
1110 pc.depthRange[0] = actualZNear; |
|
1111 pc.depthRange[1] = actualZFar; |
|
1112 pc.depthRange[2] = actualZFar - actualZNear; |
|
1113 |
|
1114 if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants)) != 0) |
|
1115 { |
|
1116 mVertexConstants = vc; |
|
1117 mDxUniformsDirty = true; |
|
1118 } |
|
1119 |
|
1120 if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants)) != 0) |
|
1121 { |
|
1122 mPixelConstants = pc; |
|
1123 mDxUniformsDirty = true; |
|
1124 } |
|
1125 } |
|
1126 |
|
1127 mForceSetViewport = false; |
|
1128 return true; |
|
1129 } |
|
1130 |
|
1131 bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count) |
|
1132 { |
|
1133 switch (mode) |
|
1134 { |
|
1135 case GL_POINTS: |
|
1136 mPrimitiveType = D3DPT_POINTLIST; |
|
1137 mPrimitiveCount = count; |
|
1138 break; |
|
1139 case GL_LINES: |
|
1140 mPrimitiveType = D3DPT_LINELIST; |
|
1141 mPrimitiveCount = count / 2; |
|
1142 break; |
|
1143 case GL_LINE_LOOP: |
|
1144 mPrimitiveType = D3DPT_LINESTRIP; |
|
1145 mPrimitiveCount = count - 1; // D3D doesn't support line loops, so we draw the last line separately |
|
1146 break; |
|
1147 case GL_LINE_STRIP: |
|
1148 mPrimitiveType = D3DPT_LINESTRIP; |
|
1149 mPrimitiveCount = count - 1; |
|
1150 break; |
|
1151 case GL_TRIANGLES: |
|
1152 mPrimitiveType = D3DPT_TRIANGLELIST; |
|
1153 mPrimitiveCount = count / 3; |
|
1154 break; |
|
1155 case GL_TRIANGLE_STRIP: |
|
1156 mPrimitiveType = D3DPT_TRIANGLESTRIP; |
|
1157 mPrimitiveCount = count - 2; |
|
1158 break; |
|
1159 case GL_TRIANGLE_FAN: |
|
1160 mPrimitiveType = D3DPT_TRIANGLEFAN; |
|
1161 mPrimitiveCount = count - 2; |
|
1162 break; |
|
1163 default: |
|
1164 return gl::error(GL_INVALID_ENUM, false); |
|
1165 } |
|
1166 |
|
1167 return mPrimitiveCount > 0; |
|
1168 } |
|
1169 |
|
1170 |
|
1171 gl::Renderbuffer *Renderer9::getNullColorbuffer(gl::Renderbuffer *depthbuffer) |
|
1172 { |
|
1173 if (!depthbuffer) |
|
1174 { |
|
1175 ERR("Unexpected null depthbuffer for depth-only FBO."); |
|
1176 return NULL; |
|
1177 } |
|
1178 |
|
1179 GLsizei width = depthbuffer->getWidth(); |
|
1180 GLsizei height = depthbuffer->getHeight(); |
|
1181 |
|
1182 // search cached nullcolorbuffers |
|
1183 for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) |
|
1184 { |
|
1185 if (mNullColorbufferCache[i].buffer != NULL && |
|
1186 mNullColorbufferCache[i].width == width && |
|
1187 mNullColorbufferCache[i].height == height) |
|
1188 { |
|
1189 mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU; |
|
1190 return mNullColorbufferCache[i].buffer; |
|
1191 } |
|
1192 } |
|
1193 |
|
1194 gl::Renderbuffer *nullbuffer = new gl::Renderbuffer(this, 0, new gl::Colorbuffer(this, width, height, GL_NONE, 0)); |
|
1195 |
|
1196 // add nullbuffer to the cache |
|
1197 NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0]; |
|
1198 for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) |
|
1199 { |
|
1200 if (mNullColorbufferCache[i].lruCount < oldest->lruCount) |
|
1201 { |
|
1202 oldest = &mNullColorbufferCache[i]; |
|
1203 } |
|
1204 } |
|
1205 |
|
1206 delete oldest->buffer; |
|
1207 oldest->buffer = nullbuffer; |
|
1208 oldest->lruCount = ++mMaxNullColorbufferLRU; |
|
1209 oldest->width = width; |
|
1210 oldest->height = height; |
|
1211 |
|
1212 return nullbuffer; |
|
1213 } |
|
1214 |
|
1215 bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) |
|
1216 { |
|
1217 // if there is no color attachment we must synthesize a NULL colorattachment |
|
1218 // to keep the D3D runtime happy. This should only be possible if depth texturing. |
|
1219 gl::Renderbuffer *renderbufferObject = NULL; |
|
1220 if (framebuffer->getColorbufferType(0) != GL_NONE) |
|
1221 { |
|
1222 renderbufferObject = framebuffer->getColorbuffer(0); |
|
1223 } |
|
1224 else |
|
1225 { |
|
1226 renderbufferObject = getNullColorbuffer(framebuffer->getDepthbuffer()); |
|
1227 } |
|
1228 if (!renderbufferObject) |
|
1229 { |
|
1230 ERR("unable to locate renderbuffer for FBO."); |
|
1231 return false; |
|
1232 } |
|
1233 |
|
1234 bool renderTargetChanged = false; |
|
1235 unsigned int renderTargetSerial = renderbufferObject->getSerial(); |
|
1236 if (renderTargetSerial != mAppliedRenderTargetSerial) |
|
1237 { |
|
1238 // Apply the render target on the device |
|
1239 IDirect3DSurface9 *renderTargetSurface = NULL; |
|
1240 |
|
1241 RenderTarget *renderTarget = renderbufferObject->getRenderTarget(); |
|
1242 if (renderTarget) |
|
1243 { |
|
1244 renderTargetSurface = RenderTarget9::makeRenderTarget9(renderTarget)->getSurface(); |
|
1245 } |
|
1246 |
|
1247 if (!renderTargetSurface) |
|
1248 { |
|
1249 ERR("render target pointer unexpectedly null."); |
|
1250 return false; // Context must be lost |
|
1251 } |
|
1252 |
|
1253 mDevice->SetRenderTarget(0, renderTargetSurface); |
|
1254 renderTargetSurface->Release(); |
|
1255 |
|
1256 mAppliedRenderTargetSerial = renderTargetSerial; |
|
1257 renderTargetChanged = true; |
|
1258 } |
|
1259 |
|
1260 gl::Renderbuffer *depthStencil = NULL; |
|
1261 unsigned int depthbufferSerial = 0; |
|
1262 unsigned int stencilbufferSerial = 0; |
|
1263 if (framebuffer->getDepthbufferType() != GL_NONE) |
|
1264 { |
|
1265 depthStencil = framebuffer->getDepthbuffer(); |
|
1266 if (!depthStencil) |
|
1267 { |
|
1268 ERR("Depth stencil pointer unexpectedly null."); |
|
1269 return false; |
|
1270 } |
|
1271 |
|
1272 depthbufferSerial = depthStencil->getSerial(); |
|
1273 } |
|
1274 else if (framebuffer->getStencilbufferType() != GL_NONE) |
|
1275 { |
|
1276 depthStencil = framebuffer->getStencilbuffer(); |
|
1277 if (!depthStencil) |
|
1278 { |
|
1279 ERR("Depth stencil pointer unexpectedly null."); |
|
1280 return false; |
|
1281 } |
|
1282 |
|
1283 stencilbufferSerial = depthStencil->getSerial(); |
|
1284 } |
|
1285 |
|
1286 if (depthbufferSerial != mAppliedDepthbufferSerial || |
|
1287 stencilbufferSerial != mAppliedStencilbufferSerial || |
|
1288 !mDepthStencilInitialized) |
|
1289 { |
|
1290 unsigned int depthSize = 0; |
|
1291 unsigned int stencilSize = 0; |
|
1292 |
|
1293 // Apply the depth stencil on the device |
|
1294 if (depthStencil) |
|
1295 { |
|
1296 IDirect3DSurface9 *depthStencilSurface = NULL; |
|
1297 RenderTarget *depthStencilRenderTarget = depthStencil->getDepthStencil(); |
|
1298 |
|
1299 if (depthStencilRenderTarget) |
|
1300 { |
|
1301 depthStencilSurface = RenderTarget9::makeRenderTarget9(depthStencilRenderTarget)->getSurface(); |
|
1302 } |
|
1303 |
|
1304 if (!depthStencilSurface) |
|
1305 { |
|
1306 ERR("depth stencil pointer unexpectedly null."); |
|
1307 return false; // Context must be lost |
|
1308 } |
|
1309 |
|
1310 mDevice->SetDepthStencilSurface(depthStencilSurface); |
|
1311 depthStencilSurface->Release(); |
|
1312 |
|
1313 depthSize = depthStencil->getDepthSize(); |
|
1314 stencilSize = depthStencil->getStencilSize(); |
|
1315 } |
|
1316 else |
|
1317 { |
|
1318 mDevice->SetDepthStencilSurface(NULL); |
|
1319 } |
|
1320 |
|
1321 if (!mDepthStencilInitialized || depthSize != mCurDepthSize) |
|
1322 { |
|
1323 mCurDepthSize = depthSize; |
|
1324 mForceSetRasterState = true; |
|
1325 } |
|
1326 |
|
1327 if (!mDepthStencilInitialized || stencilSize != mCurStencilSize) |
|
1328 { |
|
1329 mCurStencilSize = stencilSize; |
|
1330 mForceSetDepthStencilState = true; |
|
1331 } |
|
1332 |
|
1333 mAppliedDepthbufferSerial = depthbufferSerial; |
|
1334 mAppliedStencilbufferSerial = stencilbufferSerial; |
|
1335 mDepthStencilInitialized = true; |
|
1336 } |
|
1337 |
|
1338 if (renderTargetChanged || !mRenderTargetDescInitialized) |
|
1339 { |
|
1340 mForceSetScissor = true; |
|
1341 mForceSetViewport = true; |
|
1342 |
|
1343 mRenderTargetDesc.width = renderbufferObject->getWidth(); |
|
1344 mRenderTargetDesc.height = renderbufferObject->getHeight(); |
|
1345 mRenderTargetDesc.format = renderbufferObject->getActualFormat(); |
|
1346 mRenderTargetDescInitialized = true; |
|
1347 } |
|
1348 |
|
1349 return true; |
|
1350 } |
|
1351 |
|
1352 GLenum Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances) |
|
1353 { |
|
1354 TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; |
|
1355 GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, programBinary, first, count, attributes, instances); |
|
1356 if (err != GL_NO_ERROR) |
|
1357 { |
|
1358 return err; |
|
1359 } |
|
1360 |
|
1361 return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw); |
|
1362 } |
|
1363 |
|
1364 // Applies the indices and element array bindings to the Direct3D 9 device |
|
1365 GLenum Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) |
|
1366 { |
|
1367 GLenum err = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); |
|
1368 |
|
1369 if (err == GL_NO_ERROR) |
|
1370 { |
|
1371 // Directly binding the storage buffer is not supported for d3d9 |
|
1372 ASSERT(indexInfo->storage == NULL); |
|
1373 |
|
1374 if (indexInfo->serial != mAppliedIBSerial) |
|
1375 { |
|
1376 IndexBuffer9* indexBuffer = IndexBuffer9::makeIndexBuffer9(indexInfo->indexBuffer); |
|
1377 |
|
1378 mDevice->SetIndices(indexBuffer->getBuffer()); |
|
1379 mAppliedIBSerial = indexInfo->serial; |
|
1380 } |
|
1381 } |
|
1382 |
|
1383 return err; |
|
1384 } |
|
1385 |
|
1386 void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances) |
|
1387 { |
|
1388 startScene(); |
|
1389 |
|
1390 if (mode == GL_LINE_LOOP) |
|
1391 { |
|
1392 drawLineLoop(count, GL_NONE, NULL, 0, NULL); |
|
1393 } |
|
1394 else if (instances > 0) |
|
1395 { |
|
1396 StaticIndexBufferInterface *countingIB = mIndexDataManager->getCountingIndices(count); |
|
1397 if (countingIB) |
|
1398 { |
|
1399 if (mAppliedIBSerial != countingIB->getSerial()) |
|
1400 { |
|
1401 IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(countingIB->getIndexBuffer()); |
|
1402 |
|
1403 mDevice->SetIndices(indexBuffer->getBuffer()); |
|
1404 mAppliedIBSerial = countingIB->getSerial(); |
|
1405 } |
|
1406 |
|
1407 for (int i = 0; i < mRepeatDraw; i++) |
|
1408 { |
|
1409 mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount); |
|
1410 } |
|
1411 } |
|
1412 else |
|
1413 { |
|
1414 ERR("Could not create a counting index buffer for glDrawArraysInstanced."); |
|
1415 return gl::error(GL_OUT_OF_MEMORY); |
|
1416 } |
|
1417 } |
|
1418 else // Regular case |
|
1419 { |
|
1420 mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); |
|
1421 } |
|
1422 } |
|
1423 |
|
1424 void Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/) |
|
1425 { |
|
1426 startScene(); |
|
1427 |
|
1428 if (mode == GL_POINTS) |
|
1429 { |
|
1430 drawIndexedPoints(count, type, indices, elementArrayBuffer); |
|
1431 } |
|
1432 else if (mode == GL_LINE_LOOP) |
|
1433 { |
|
1434 drawLineLoop(count, type, indices, indexInfo.minIndex, elementArrayBuffer); |
|
1435 } |
|
1436 else |
|
1437 { |
|
1438 for (int i = 0; i < mRepeatDraw; i++) |
|
1439 { |
|
1440 GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1; |
|
1441 mDevice->DrawIndexedPrimitive(mPrimitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount); |
|
1442 } |
|
1443 } |
|
1444 } |
|
1445 |
|
1446 void Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) |
|
1447 { |
|
1448 // Get the raw indices for an indexed draw |
|
1449 if (type != GL_NONE && elementArrayBuffer) |
|
1450 { |
|
1451 gl::Buffer *indexBuffer = elementArrayBuffer; |
|
1452 BufferStorage *storage = indexBuffer->getStorage(); |
|
1453 intptr_t offset = reinterpret_cast<intptr_t>(indices); |
|
1454 indices = static_cast<const GLubyte*>(storage->getData()) + offset; |
|
1455 } |
|
1456 |
|
1457 unsigned int startIndex = 0; |
|
1458 |
|
1459 if (get32BitIndexSupport()) |
|
1460 { |
|
1461 if (!mLineLoopIB) |
|
1462 { |
|
1463 mLineLoopIB = new StreamingIndexBufferInterface(this); |
|
1464 if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT)) |
|
1465 { |
|
1466 delete mLineLoopIB; |
|
1467 mLineLoopIB = NULL; |
|
1468 |
|
1469 ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP."); |
|
1470 return gl::error(GL_OUT_OF_MEMORY); |
|
1471 } |
|
1472 } |
|
1473 |
|
1474 if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int))) |
|
1475 { |
|
1476 ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); |
|
1477 return gl::error(GL_OUT_OF_MEMORY); |
|
1478 } |
|
1479 |
|
1480 // Checked by Renderer9::applyPrimitiveType |
|
1481 ASSERT(count >= 0); |
|
1482 |
|
1483 const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int); |
|
1484 if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)) |
|
1485 { |
|
1486 ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP."); |
|
1487 return gl::error(GL_OUT_OF_MEMORY); |
|
1488 } |
|
1489 |
|
1490 void* mappedMemory = NULL; |
|
1491 unsigned int offset = 0; |
|
1492 if (!mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)) |
|
1493 { |
|
1494 ERR("Could not map index buffer for GL_LINE_LOOP."); |
|
1495 return gl::error(GL_OUT_OF_MEMORY); |
|
1496 } |
|
1497 |
|
1498 startIndex = static_cast<unsigned int>(offset) / 4; |
|
1499 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory); |
|
1500 |
|
1501 switch (type) |
|
1502 { |
|
1503 case GL_NONE: // Non-indexed draw |
|
1504 for (int i = 0; i < count; i++) |
|
1505 { |
|
1506 data[i] = i; |
|
1507 } |
|
1508 data[count] = 0; |
|
1509 break; |
|
1510 case GL_UNSIGNED_BYTE: |
|
1511 for (int i = 0; i < count; i++) |
|
1512 { |
|
1513 data[i] = static_cast<const GLubyte*>(indices)[i]; |
|
1514 } |
|
1515 data[count] = static_cast<const GLubyte*>(indices)[0]; |
|
1516 break; |
|
1517 case GL_UNSIGNED_SHORT: |
|
1518 for (int i = 0; i < count; i++) |
|
1519 { |
|
1520 data[i] = static_cast<const GLushort*>(indices)[i]; |
|
1521 } |
|
1522 data[count] = static_cast<const GLushort*>(indices)[0]; |
|
1523 break; |
|
1524 case GL_UNSIGNED_INT: |
|
1525 for (int i = 0; i < count; i++) |
|
1526 { |
|
1527 data[i] = static_cast<const GLuint*>(indices)[i]; |
|
1528 } |
|
1529 data[count] = static_cast<const GLuint*>(indices)[0]; |
|
1530 break; |
|
1531 default: UNREACHABLE(); |
|
1532 } |
|
1533 |
|
1534 if (!mLineLoopIB->unmapBuffer()) |
|
1535 { |
|
1536 ERR("Could not unmap index buffer for GL_LINE_LOOP."); |
|
1537 return gl::error(GL_OUT_OF_MEMORY); |
|
1538 } |
|
1539 } |
|
1540 else |
|
1541 { |
|
1542 if (!mLineLoopIB) |
|
1543 { |
|
1544 mLineLoopIB = new StreamingIndexBufferInterface(this); |
|
1545 if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT)) |
|
1546 { |
|
1547 delete mLineLoopIB; |
|
1548 mLineLoopIB = NULL; |
|
1549 |
|
1550 ERR("Could not create a 16-bit looping index buffer for GL_LINE_LOOP."); |
|
1551 return gl::error(GL_OUT_OF_MEMORY); |
|
1552 } |
|
1553 } |
|
1554 |
|
1555 // Checked by Renderer9::applyPrimitiveType |
|
1556 ASSERT(count >= 0); |
|
1557 |
|
1558 if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned short>::max() / sizeof(unsigned short))) |
|
1559 { |
|
1560 ERR("Could not create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required."); |
|
1561 return gl::error(GL_OUT_OF_MEMORY); |
|
1562 } |
|
1563 |
|
1564 const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned short); |
|
1565 if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT)) |
|
1566 { |
|
1567 ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP."); |
|
1568 return gl::error(GL_OUT_OF_MEMORY); |
|
1569 } |
|
1570 |
|
1571 void* mappedMemory = NULL; |
|
1572 unsigned int offset; |
|
1573 if (mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)) |
|
1574 { |
|
1575 ERR("Could not map index buffer for GL_LINE_LOOP."); |
|
1576 return gl::error(GL_OUT_OF_MEMORY); |
|
1577 } |
|
1578 |
|
1579 startIndex = static_cast<unsigned int>(offset) / 2; |
|
1580 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory); |
|
1581 |
|
1582 switch (type) |
|
1583 { |
|
1584 case GL_NONE: // Non-indexed draw |
|
1585 for (int i = 0; i < count; i++) |
|
1586 { |
|
1587 data[i] = i; |
|
1588 } |
|
1589 data[count] = 0; |
|
1590 break; |
|
1591 case GL_UNSIGNED_BYTE: |
|
1592 for (int i = 0; i < count; i++) |
|
1593 { |
|
1594 data[i] = static_cast<const GLubyte*>(indices)[i]; |
|
1595 } |
|
1596 data[count] = static_cast<const GLubyte*>(indices)[0]; |
|
1597 break; |
|
1598 case GL_UNSIGNED_SHORT: |
|
1599 for (int i = 0; i < count; i++) |
|
1600 { |
|
1601 data[i] = static_cast<const GLushort*>(indices)[i]; |
|
1602 } |
|
1603 data[count] = static_cast<const GLushort*>(indices)[0]; |
|
1604 break; |
|
1605 case GL_UNSIGNED_INT: |
|
1606 for (int i = 0; i < count; i++) |
|
1607 { |
|
1608 data[i] = static_cast<const GLuint*>(indices)[i]; |
|
1609 } |
|
1610 data[count] = static_cast<const GLuint*>(indices)[0]; |
|
1611 break; |
|
1612 default: UNREACHABLE(); |
|
1613 } |
|
1614 |
|
1615 if (!mLineLoopIB->unmapBuffer()) |
|
1616 { |
|
1617 ERR("Could not unmap index buffer for GL_LINE_LOOP."); |
|
1618 return gl::error(GL_OUT_OF_MEMORY); |
|
1619 } |
|
1620 } |
|
1621 |
|
1622 if (mAppliedIBSerial != mLineLoopIB->getSerial()) |
|
1623 { |
|
1624 IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(mLineLoopIB->getIndexBuffer()); |
|
1625 |
|
1626 mDevice->SetIndices(indexBuffer->getBuffer()); |
|
1627 mAppliedIBSerial = mLineLoopIB->getSerial(); |
|
1628 } |
|
1629 |
|
1630 mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); |
|
1631 } |
|
1632 |
|
1633 template <typename T> |
|
1634 static void drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices) |
|
1635 { |
|
1636 for (int i = 0; i < count; i++) |
|
1637 { |
|
1638 unsigned int indexValue = static_cast<unsigned int>(static_cast<const T*>(indices)[i]); |
|
1639 device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1); |
|
1640 } |
|
1641 } |
|
1642 |
|
1643 void Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer) |
|
1644 { |
|
1645 // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call |
|
1646 // for each individual point. This call is not expected to happen often. |
|
1647 |
|
1648 if (elementArrayBuffer) |
|
1649 { |
|
1650 BufferStorage *storage = elementArrayBuffer->getStorage(); |
|
1651 intptr_t offset = reinterpret_cast<intptr_t>(indices); |
|
1652 indices = static_cast<const GLubyte*>(storage->getData()) + offset; |
|
1653 } |
|
1654 |
|
1655 switch (type) |
|
1656 { |
|
1657 case GL_UNSIGNED_BYTE: drawPoints<GLubyte>(mDevice, count, indices); break; |
|
1658 case GL_UNSIGNED_SHORT: drawPoints<GLushort>(mDevice, count, indices); break; |
|
1659 case GL_UNSIGNED_INT: drawPoints<GLuint>(mDevice, count, indices); break; |
|
1660 default: UNREACHABLE(); |
|
1661 } |
|
1662 } |
|
1663 |
|
1664 void Renderer9::applyShaders(gl::ProgramBinary *programBinary) |
|
1665 { |
|
1666 unsigned int programBinarySerial = programBinary->getSerial(); |
|
1667 if (programBinarySerial != mAppliedProgramBinarySerial) |
|
1668 { |
|
1669 ShaderExecutable *vertexExe = programBinary->getVertexExecutable(); |
|
1670 ShaderExecutable *pixelExe = programBinary->getPixelExecutable(); |
|
1671 |
|
1672 IDirect3DVertexShader9 *vertexShader = NULL; |
|
1673 if (vertexExe) vertexShader = ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader(); |
|
1674 |
|
1675 IDirect3DPixelShader9 *pixelShader = NULL; |
|
1676 if (pixelExe) pixelShader = ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader(); |
|
1677 |
|
1678 mDevice->SetPixelShader(pixelShader); |
|
1679 mDevice->SetVertexShader(vertexShader); |
|
1680 programBinary->dirtyAllUniforms(); |
|
1681 mDxUniformsDirty = true; |
|
1682 |
|
1683 mAppliedProgramBinarySerial = programBinarySerial; |
|
1684 } |
|
1685 } |
|
1686 |
|
1687 void Renderer9::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray) |
|
1688 { |
|
1689 for (std::vector<gl::Uniform*>::const_iterator ub = uniformArray->begin(), ue = uniformArray->end(); ub != ue; ++ub) |
|
1690 { |
|
1691 gl::Uniform *targetUniform = *ub; |
|
1692 |
|
1693 if (targetUniform->dirty) |
|
1694 { |
|
1695 GLfloat *f = (GLfloat*)targetUniform->data; |
|
1696 GLint *i = (GLint*)targetUniform->data; |
|
1697 |
|
1698 switch (targetUniform->type) |
|
1699 { |
|
1700 case GL_SAMPLER_2D: |
|
1701 case GL_SAMPLER_CUBE: |
|
1702 break; |
|
1703 case GL_BOOL: |
|
1704 case GL_BOOL_VEC2: |
|
1705 case GL_BOOL_VEC3: |
|
1706 case GL_BOOL_VEC4: |
|
1707 applyUniformnbv(targetUniform, i); |
|
1708 break; |
|
1709 case GL_FLOAT: |
|
1710 case GL_FLOAT_VEC2: |
|
1711 case GL_FLOAT_VEC3: |
|
1712 case GL_FLOAT_VEC4: |
|
1713 case GL_FLOAT_MAT2: |
|
1714 case GL_FLOAT_MAT3: |
|
1715 case GL_FLOAT_MAT4: |
|
1716 applyUniformnfv(targetUniform, f); |
|
1717 break; |
|
1718 case GL_INT: |
|
1719 case GL_INT_VEC2: |
|
1720 case GL_INT_VEC3: |
|
1721 case GL_INT_VEC4: |
|
1722 applyUniformniv(targetUniform, i); |
|
1723 break; |
|
1724 default: |
|
1725 UNREACHABLE(); |
|
1726 } |
|
1727 |
|
1728 targetUniform->dirty = false; |
|
1729 } |
|
1730 } |
|
1731 |
|
1732 // Driver uniforms |
|
1733 if (mDxUniformsDirty) |
|
1734 { |
|
1735 mDevice->SetVertexShaderConstantF(0, (float*)&mVertexConstants, sizeof(dx_VertexConstants) / sizeof(float[4])); |
|
1736 mDevice->SetPixelShaderConstantF(0, (float*)&mPixelConstants, sizeof(dx_PixelConstants) / sizeof(float[4])); |
|
1737 mDxUniformsDirty = false; |
|
1738 } |
|
1739 } |
|
1740 |
|
1741 void Renderer9::applyUniformnfv(gl::Uniform *targetUniform, const GLfloat *v) |
|
1742 { |
|
1743 if (targetUniform->psRegisterIndex >= 0) |
|
1744 { |
|
1745 mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount); |
|
1746 } |
|
1747 |
|
1748 if (targetUniform->vsRegisterIndex >= 0) |
|
1749 { |
|
1750 mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount); |
|
1751 } |
|
1752 } |
|
1753 |
|
1754 void Renderer9::applyUniformniv(gl::Uniform *targetUniform, const GLint *v) |
|
1755 { |
|
1756 ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); |
|
1757 GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; |
|
1758 |
|
1759 for (unsigned int i = 0; i < targetUniform->registerCount; i++) |
|
1760 { |
|
1761 vector[i][0] = (GLfloat)v[4 * i + 0]; |
|
1762 vector[i][1] = (GLfloat)v[4 * i + 1]; |
|
1763 vector[i][2] = (GLfloat)v[4 * i + 2]; |
|
1764 vector[i][3] = (GLfloat)v[4 * i + 3]; |
|
1765 } |
|
1766 |
|
1767 applyUniformnfv(targetUniform, (GLfloat*)vector); |
|
1768 } |
|
1769 |
|
1770 void Renderer9::applyUniformnbv(gl::Uniform *targetUniform, const GLint *v) |
|
1771 { |
|
1772 ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); |
|
1773 GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; |
|
1774 |
|
1775 for (unsigned int i = 0; i < targetUniform->registerCount; i++) |
|
1776 { |
|
1777 vector[i][0] = (v[4 * i + 0] == GL_FALSE) ? 0.0f : 1.0f; |
|
1778 vector[i][1] = (v[4 * i + 1] == GL_FALSE) ? 0.0f : 1.0f; |
|
1779 vector[i][2] = (v[4 * i + 2] == GL_FALSE) ? 0.0f : 1.0f; |
|
1780 vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f; |
|
1781 } |
|
1782 |
|
1783 applyUniformnfv(targetUniform, (GLfloat*)vector); |
|
1784 } |
|
1785 |
|
1786 void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) |
|
1787 { |
|
1788 D3DCOLOR color = D3DCOLOR_ARGB(gl::unorm<8>(clearParams.colorClearValue.alpha), |
|
1789 gl::unorm<8>(clearParams.colorClearValue.red), |
|
1790 gl::unorm<8>(clearParams.colorClearValue.green), |
|
1791 gl::unorm<8>(clearParams.colorClearValue.blue)); |
|
1792 float depth = gl::clamp01(clearParams.depthClearValue); |
|
1793 int stencil = clearParams.stencilClearValue & 0x000000FF; |
|
1794 |
|
1795 unsigned int stencilUnmasked = 0x0; |
|
1796 if ((clearParams.mask & GL_STENCIL_BUFFER_BIT) && frameBuffer->hasStencil()) |
|
1797 { |
|
1798 unsigned int stencilSize = gl::GetStencilSize(frameBuffer->getStencilbuffer()->getActualFormat()); |
|
1799 stencilUnmasked = (0x1 << stencilSize) - 1; |
|
1800 } |
|
1801 |
|
1802 bool alphaUnmasked = (gl::GetAlphaSize(mRenderTargetDesc.format) == 0) || clearParams.colorMaskAlpha; |
|
1803 |
|
1804 const bool needMaskedStencilClear = (clearParams.mask & GL_STENCIL_BUFFER_BIT) && |
|
1805 (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; |
|
1806 const bool needMaskedColorClear = (clearParams.mask & GL_COLOR_BUFFER_BIT) && |
|
1807 !(clearParams.colorMaskRed && clearParams.colorMaskGreen && |
|
1808 clearParams.colorMaskBlue && alphaUnmasked); |
|
1809 |
|
1810 if (needMaskedColorClear || needMaskedStencilClear) |
|
1811 { |
|
1812 // State which is altered in all paths from this point to the clear call is saved. |
|
1813 // State which is altered in only some paths will be flagged dirty in the case that |
|
1814 // that path is taken. |
|
1815 HRESULT hr; |
|
1816 if (mMaskedClearSavedState == NULL) |
|
1817 { |
|
1818 hr = mDevice->BeginStateBlock(); |
|
1819 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); |
|
1820 |
|
1821 mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); |
|
1822 mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); |
|
1823 mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); |
|
1824 mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); |
|
1825 mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); |
|
1826 mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); |
|
1827 mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); |
|
1828 mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); |
|
1829 mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); |
|
1830 mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); |
|
1831 mDevice->SetPixelShader(NULL); |
|
1832 mDevice->SetVertexShader(NULL); |
|
1833 mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); |
|
1834 mDevice->SetStreamSource(0, NULL, 0, 0); |
|
1835 mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); |
|
1836 mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); |
|
1837 mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); |
|
1838 mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); |
|
1839 mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); |
|
1840 mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); |
|
1841 mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); |
|
1842 |
|
1843 for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) |
|
1844 { |
|
1845 mDevice->SetStreamSourceFreq(i, 1); |
|
1846 } |
|
1847 |
|
1848 hr = mDevice->EndStateBlock(&mMaskedClearSavedState); |
|
1849 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); |
|
1850 } |
|
1851 |
|
1852 ASSERT(mMaskedClearSavedState != NULL); |
|
1853 |
|
1854 if (mMaskedClearSavedState != NULL) |
|
1855 { |
|
1856 hr = mMaskedClearSavedState->Capture(); |
|
1857 ASSERT(SUCCEEDED(hr)); |
|
1858 } |
|
1859 |
|
1860 mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); |
|
1861 mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); |
|
1862 mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); |
|
1863 mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); |
|
1864 mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); |
|
1865 mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); |
|
1866 mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); |
|
1867 mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); |
|
1868 |
|
1869 if (clearParams.mask & GL_COLOR_BUFFER_BIT) |
|
1870 { |
|
1871 mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, |
|
1872 gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, |
|
1873 clearParams.colorMaskGreen, |
|
1874 clearParams.colorMaskBlue, |
|
1875 clearParams.colorMaskAlpha)); |
|
1876 } |
|
1877 else |
|
1878 { |
|
1879 mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); |
|
1880 } |
|
1881 |
|
1882 if (stencilUnmasked != 0x0 && (clearParams.mask & GL_STENCIL_BUFFER_BIT)) |
|
1883 { |
|
1884 mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); |
|
1885 mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); |
|
1886 mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); |
|
1887 mDevice->SetRenderState(D3DRS_STENCILREF, stencil); |
|
1888 mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, clearParams.stencilWriteMask); |
|
1889 mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); |
|
1890 mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); |
|
1891 mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); |
|
1892 } |
|
1893 else |
|
1894 { |
|
1895 mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); |
|
1896 } |
|
1897 |
|
1898 mDevice->SetPixelShader(NULL); |
|
1899 mDevice->SetVertexShader(NULL); |
|
1900 mDevice->SetFVF(D3DFVF_XYZRHW); |
|
1901 mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); |
|
1902 mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); |
|
1903 mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); |
|
1904 mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); |
|
1905 mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); |
|
1906 mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); |
|
1907 mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); |
|
1908 |
|
1909 for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) |
|
1910 { |
|
1911 mDevice->SetStreamSourceFreq(i, 1); |
|
1912 } |
|
1913 |
|
1914 float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges |
|
1915 quad[0][0] = -0.5f; |
|
1916 quad[0][1] = mRenderTargetDesc.height - 0.5f; |
|
1917 quad[0][2] = 0.0f; |
|
1918 quad[0][3] = 1.0f; |
|
1919 |
|
1920 quad[1][0] = mRenderTargetDesc.width - 0.5f; |
|
1921 quad[1][1] = mRenderTargetDesc.height - 0.5f; |
|
1922 quad[1][2] = 0.0f; |
|
1923 quad[1][3] = 1.0f; |
|
1924 |
|
1925 quad[2][0] = -0.5f; |
|
1926 quad[2][1] = -0.5f; |
|
1927 quad[2][2] = 0.0f; |
|
1928 quad[2][3] = 1.0f; |
|
1929 |
|
1930 quad[3][0] = mRenderTargetDesc.width - 0.5f; |
|
1931 quad[3][1] = -0.5f; |
|
1932 quad[3][2] = 0.0f; |
|
1933 quad[3][3] = 1.0f; |
|
1934 |
|
1935 startScene(); |
|
1936 mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4])); |
|
1937 |
|
1938 if (clearParams.mask & GL_DEPTH_BUFFER_BIT) |
|
1939 { |
|
1940 mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); |
|
1941 mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); |
|
1942 mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); |
|
1943 } |
|
1944 |
|
1945 if (mMaskedClearSavedState != NULL) |
|
1946 { |
|
1947 mMaskedClearSavedState->Apply(); |
|
1948 } |
|
1949 } |
|
1950 else if (clearParams.mask) |
|
1951 { |
|
1952 DWORD dxClearFlags = 0; |
|
1953 if (clearParams.mask & GL_COLOR_BUFFER_BIT) |
|
1954 { |
|
1955 dxClearFlags |= D3DCLEAR_TARGET; |
|
1956 } |
|
1957 if (clearParams.mask & GL_DEPTH_BUFFER_BIT) |
|
1958 { |
|
1959 dxClearFlags |= D3DCLEAR_ZBUFFER; |
|
1960 } |
|
1961 if (clearParams.mask & GL_STENCIL_BUFFER_BIT) |
|
1962 { |
|
1963 dxClearFlags |= D3DCLEAR_STENCIL; |
|
1964 } |
|
1965 |
|
1966 mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil); |
|
1967 } |
|
1968 } |
|
1969 |
|
1970 void Renderer9::markAllStateDirty() |
|
1971 { |
|
1972 mAppliedRenderTargetSerial = 0; |
|
1973 mAppliedDepthbufferSerial = 0; |
|
1974 mAppliedStencilbufferSerial = 0; |
|
1975 mDepthStencilInitialized = false; |
|
1976 mRenderTargetDescInitialized = false; |
|
1977 |
|
1978 mForceSetDepthStencilState = true; |
|
1979 mForceSetRasterState = true; |
|
1980 mForceSetScissor = true; |
|
1981 mForceSetViewport = true; |
|
1982 mForceSetBlendState = true; |
|
1983 |
|
1984 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++) |
|
1985 { |
|
1986 mForceSetVertexSamplerStates[i] = true; |
|
1987 mCurVertexTextureSerials[i] = 0; |
|
1988 } |
|
1989 for (unsigned int i = 0; i < gl::MAX_TEXTURE_IMAGE_UNITS; i++) |
|
1990 { |
|
1991 mForceSetPixelSamplerStates[i] = true; |
|
1992 mCurPixelTextureSerials[i] = 0; |
|
1993 } |
|
1994 |
|
1995 mAppliedIBSerial = 0; |
|
1996 mAppliedProgramBinarySerial = 0; |
|
1997 mDxUniformsDirty = true; |
|
1998 |
|
1999 mVertexDeclarationCache.markStateDirty(); |
|
2000 } |
|
2001 |
|
2002 void Renderer9::releaseDeviceResources() |
|
2003 { |
|
2004 while (!mEventQueryPool.empty()) |
|
2005 { |
|
2006 mEventQueryPool.back()->Release(); |
|
2007 mEventQueryPool.pop_back(); |
|
2008 } |
|
2009 |
|
2010 if (mMaskedClearSavedState) |
|
2011 { |
|
2012 mMaskedClearSavedState->Release(); |
|
2013 mMaskedClearSavedState = NULL; |
|
2014 } |
|
2015 |
|
2016 mVertexShaderCache.clear(); |
|
2017 mPixelShaderCache.clear(); |
|
2018 |
|
2019 delete mBlit; |
|
2020 mBlit = NULL; |
|
2021 |
|
2022 delete mVertexDataManager; |
|
2023 mVertexDataManager = NULL; |
|
2024 |
|
2025 delete mIndexDataManager; |
|
2026 mIndexDataManager = NULL; |
|
2027 |
|
2028 delete mLineLoopIB; |
|
2029 mLineLoopIB = NULL; |
|
2030 |
|
2031 for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) |
|
2032 { |
|
2033 delete mNullColorbufferCache[i].buffer; |
|
2034 mNullColorbufferCache[i].buffer = NULL; |
|
2035 } |
|
2036 |
|
2037 } |
|
2038 |
|
2039 |
|
2040 void Renderer9::notifyDeviceLost() |
|
2041 { |
|
2042 mDeviceLost = true; |
|
2043 mDisplay->notifyDeviceLost(); |
|
2044 } |
|
2045 |
|
2046 bool Renderer9::isDeviceLost() |
|
2047 { |
|
2048 return mDeviceLost; |
|
2049 } |
|
2050 |
|
2051 // set notify to true to broadcast a message to all contexts of the device loss |
|
2052 bool Renderer9::testDeviceLost(bool notify) |
|
2053 { |
|
2054 HRESULT status = S_OK; |
|
2055 |
|
2056 if (mDeviceEx) |
|
2057 { |
|
2058 status = mDeviceEx->CheckDeviceState(NULL); |
|
2059 } |
|
2060 else if (mDevice) |
|
2061 { |
|
2062 status = mDevice->TestCooperativeLevel(); |
|
2063 } |
|
2064 else |
|
2065 { |
|
2066 // No device yet, so no reset required |
|
2067 } |
|
2068 |
|
2069 bool isLost = FAILED(status) || d3d9::isDeviceLostError(status); |
|
2070 |
|
2071 if (isLost) |
|
2072 { |
|
2073 // ensure we note the device loss -- |
|
2074 // we'll probably get this done again by notifyDeviceLost |
|
2075 // but best to remember it! |
|
2076 // Note that we don't want to clear the device loss status here |
|
2077 // -- this needs to be done by resetDevice |
|
2078 mDeviceLost = true; |
|
2079 if (notify) |
|
2080 { |
|
2081 notifyDeviceLost(); |
|
2082 } |
|
2083 } |
|
2084 |
|
2085 return isLost; |
|
2086 } |
|
2087 |
|
2088 bool Renderer9::testDeviceResettable() |
|
2089 { |
|
2090 HRESULT status = D3D_OK; |
|
2091 |
|
2092 if (mDeviceEx) |
|
2093 { |
|
2094 status = mDeviceEx->CheckDeviceState(NULL); |
|
2095 } |
|
2096 else if (mDevice) |
|
2097 { |
|
2098 status = mDevice->TestCooperativeLevel(); |
|
2099 } |
|
2100 |
|
2101 // On D3D9Ex, DEVICELOST represents a hung device that needs to be restarted |
|
2102 // DEVICEREMOVED indicates the device has been stopped and must be recreated |
|
2103 switch (status) |
|
2104 { |
|
2105 case D3DERR_DEVICENOTRESET: |
|
2106 case D3DERR_DEVICEHUNG: |
|
2107 return true; |
|
2108 case D3DERR_DEVICELOST: |
|
2109 return (mDeviceEx != NULL); |
|
2110 case D3DERR_DEVICEREMOVED: |
|
2111 UNIMPLEMENTED(); |
|
2112 return false; |
|
2113 default: |
|
2114 return false; |
|
2115 } |
|
2116 } |
|
2117 |
|
2118 bool Renderer9::resetDevice() |
|
2119 { |
|
2120 releaseDeviceResources(); |
|
2121 |
|
2122 D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); |
|
2123 |
|
2124 HRESULT result = D3D_OK; |
|
2125 bool lost = testDeviceLost(false); |
|
2126 int attempts = 3; |
|
2127 |
|
2128 while (lost && attempts > 0) |
|
2129 { |
|
2130 if (mDeviceEx) |
|
2131 { |
|
2132 Sleep(500); // Give the graphics driver some CPU time |
|
2133 result = mDeviceEx->ResetEx(&presentParameters, NULL); |
|
2134 } |
|
2135 else |
|
2136 { |
|
2137 result = mDevice->TestCooperativeLevel(); |
|
2138 while (result == D3DERR_DEVICELOST) |
|
2139 { |
|
2140 Sleep(100); // Give the graphics driver some CPU time |
|
2141 result = mDevice->TestCooperativeLevel(); |
|
2142 } |
|
2143 |
|
2144 if (result == D3DERR_DEVICENOTRESET) |
|
2145 { |
|
2146 result = mDevice->Reset(&presentParameters); |
|
2147 } |
|
2148 } |
|
2149 |
|
2150 lost = testDeviceLost(false); |
|
2151 attempts --; |
|
2152 } |
|
2153 |
|
2154 if (FAILED(result)) |
|
2155 { |
|
2156 ERR("Reset/ResetEx failed multiple times: 0x%08X", result); |
|
2157 return false; |
|
2158 } |
|
2159 |
|
2160 // reset device defaults |
|
2161 initializeDevice(); |
|
2162 mDeviceLost = false; |
|
2163 |
|
2164 return true; |
|
2165 } |
|
2166 |
|
2167 DWORD Renderer9::getAdapterVendor() const |
|
2168 { |
|
2169 return mAdapterIdentifier.VendorId; |
|
2170 } |
|
2171 |
|
2172 std::string Renderer9::getRendererDescription() const |
|
2173 { |
|
2174 std::ostringstream rendererString; |
|
2175 |
|
2176 rendererString << mAdapterIdentifier.Description; |
|
2177 if (getShareHandleSupport()) |
|
2178 { |
|
2179 rendererString << " Direct3D9Ex"; |
|
2180 } |
|
2181 else |
|
2182 { |
|
2183 rendererString << " Direct3D9"; |
|
2184 } |
|
2185 |
|
2186 rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion); |
|
2187 rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); |
|
2188 |
|
2189 return rendererString.str(); |
|
2190 } |
|
2191 |
|
2192 GUID Renderer9::getAdapterIdentifier() const |
|
2193 { |
|
2194 return mAdapterIdentifier.DeviceIdentifier; |
|
2195 } |
|
2196 |
|
2197 void Renderer9::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray) |
|
2198 { |
|
2199 for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++) |
|
2200 { |
|
2201 HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format, |
|
2202 TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL); |
|
2203 |
|
2204 multiSampleArray[multiSampleIndex] = SUCCEEDED(result); |
|
2205 } |
|
2206 } |
|
2207 |
|
2208 bool Renderer9::getBGRATextureSupport() const |
|
2209 { |
|
2210 // DirectX 9 always supports BGRA |
|
2211 return true; |
|
2212 } |
|
2213 |
|
2214 bool Renderer9::getDXT1TextureSupport() |
|
2215 { |
|
2216 return mDXT1TextureSupport; |
|
2217 } |
|
2218 |
|
2219 bool Renderer9::getDXT3TextureSupport() |
|
2220 { |
|
2221 return mDXT3TextureSupport; |
|
2222 } |
|
2223 |
|
2224 bool Renderer9::getDXT5TextureSupport() |
|
2225 { |
|
2226 return mDXT5TextureSupport; |
|
2227 } |
|
2228 |
|
2229 bool Renderer9::getDepthTextureSupport() const |
|
2230 { |
|
2231 return mDepthTextureSupport; |
|
2232 } |
|
2233 |
|
2234 bool Renderer9::getFloat32TextureSupport(bool *filtering, bool *renderable) |
|
2235 { |
|
2236 *filtering = mFloat32FilterSupport; |
|
2237 *renderable = mFloat32RenderSupport; |
|
2238 return mFloat32TextureSupport; |
|
2239 } |
|
2240 |
|
2241 bool Renderer9::getFloat16TextureSupport(bool *filtering, bool *renderable) |
|
2242 { |
|
2243 *filtering = mFloat16FilterSupport; |
|
2244 *renderable = mFloat16RenderSupport; |
|
2245 return mFloat16TextureSupport; |
|
2246 } |
|
2247 |
|
2248 bool Renderer9::getLuminanceTextureSupport() |
|
2249 { |
|
2250 return mLuminanceTextureSupport; |
|
2251 } |
|
2252 |
|
2253 bool Renderer9::getLuminanceAlphaTextureSupport() |
|
2254 { |
|
2255 return mLuminanceAlphaTextureSupport; |
|
2256 } |
|
2257 |
|
2258 bool Renderer9::getTextureFilterAnisotropySupport() const |
|
2259 { |
|
2260 return mSupportsTextureFilterAnisotropy; |
|
2261 } |
|
2262 |
|
2263 float Renderer9::getTextureMaxAnisotropy() const |
|
2264 { |
|
2265 if (mSupportsTextureFilterAnisotropy) |
|
2266 { |
|
2267 return static_cast<float>(mDeviceCaps.MaxAnisotropy); |
|
2268 } |
|
2269 return 1.0f; |
|
2270 } |
|
2271 |
|
2272 bool Renderer9::getEventQuerySupport() |
|
2273 { |
|
2274 return mEventQuerySupport; |
|
2275 } |
|
2276 |
|
2277 unsigned int Renderer9::getMaxVertexTextureImageUnits() const |
|
2278 { |
|
2279 META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS); |
|
2280 return mVertexTextureSupport ? MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 : 0; |
|
2281 } |
|
2282 |
|
2283 unsigned int Renderer9::getMaxCombinedTextureImageUnits() const |
|
2284 { |
|
2285 return gl::MAX_TEXTURE_IMAGE_UNITS + getMaxVertexTextureImageUnits(); |
|
2286 } |
|
2287 |
|
2288 unsigned int Renderer9::getReservedVertexUniformVectors() const |
|
2289 { |
|
2290 return 2; // dx_ViewAdjust and dx_DepthRange. |
|
2291 } |
|
2292 |
|
2293 unsigned int Renderer9::getReservedFragmentUniformVectors() const |
|
2294 { |
|
2295 return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. |
|
2296 } |
|
2297 |
|
2298 unsigned int Renderer9::getMaxVertexUniformVectors() const |
|
2299 { |
|
2300 return MAX_VERTEX_CONSTANT_VECTORS_D3D9 - getReservedVertexUniformVectors(); |
|
2301 } |
|
2302 |
|
2303 unsigned int Renderer9::getMaxFragmentUniformVectors() const |
|
2304 { |
|
2305 const int maxPixelConstantVectors = (getMajorShaderModel() >= 3) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 : MAX_PIXEL_CONSTANT_VECTORS_SM2; |
|
2306 |
|
2307 return maxPixelConstantVectors - getReservedFragmentUniformVectors(); |
|
2308 } |
|
2309 |
|
2310 unsigned int Renderer9::getMaxVaryingVectors() const |
|
2311 { |
|
2312 return (getMajorShaderModel() >= 3) ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2; |
|
2313 } |
|
2314 |
|
2315 bool Renderer9::getNonPower2TextureSupport() const |
|
2316 { |
|
2317 return mSupportsNonPower2Textures; |
|
2318 } |
|
2319 |
|
2320 bool Renderer9::getOcclusionQuerySupport() const |
|
2321 { |
|
2322 return mOcclusionQuerySupport; |
|
2323 } |
|
2324 |
|
2325 bool Renderer9::getInstancingSupport() const |
|
2326 { |
|
2327 return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); |
|
2328 } |
|
2329 |
|
2330 bool Renderer9::getShareHandleSupport() const |
|
2331 { |
|
2332 // PIX doesn't seem to support using share handles, so disable them. |
|
2333 return (mD3d9Ex != NULL) && !gl::perfActive(); |
|
2334 } |
|
2335 |
|
2336 bool Renderer9::getDerivativeInstructionSupport() const |
|
2337 { |
|
2338 return (mDeviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; |
|
2339 } |
|
2340 |
|
2341 bool Renderer9::getPostSubBufferSupport() const |
|
2342 { |
|
2343 return true; |
|
2344 } |
|
2345 |
|
2346 int Renderer9::getMajorShaderModel() const |
|
2347 { |
|
2348 return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion); |
|
2349 } |
|
2350 |
|
2351 float Renderer9::getMaxPointSize() const |
|
2352 { |
|
2353 // Point size clamped at 1.0f for SM2 |
|
2354 return getMajorShaderModel() == 3 ? mDeviceCaps.MaxPointSize : 1.0f; |
|
2355 } |
|
2356 |
|
2357 int Renderer9::getMaxViewportDimension() const |
|
2358 { |
|
2359 int maxTextureDimension = std::min(std::min(getMaxTextureWidth(), getMaxTextureHeight()), |
|
2360 (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE); |
|
2361 return maxTextureDimension; |
|
2362 } |
|
2363 |
|
2364 int Renderer9::getMaxTextureWidth() const |
|
2365 { |
|
2366 return (int)mDeviceCaps.MaxTextureWidth; |
|
2367 } |
|
2368 |
|
2369 int Renderer9::getMaxTextureHeight() const |
|
2370 { |
|
2371 return (int)mDeviceCaps.MaxTextureHeight; |
|
2372 } |
|
2373 |
|
2374 bool Renderer9::get32BitIndexSupport() const |
|
2375 { |
|
2376 return mDeviceCaps.MaxVertexIndex >= (1 << 16); |
|
2377 } |
|
2378 |
|
2379 DWORD Renderer9::getCapsDeclTypes() const |
|
2380 { |
|
2381 return mDeviceCaps.DeclTypes; |
|
2382 } |
|
2383 |
|
2384 int Renderer9::getMinSwapInterval() const |
|
2385 { |
|
2386 return mMinSwapInterval; |
|
2387 } |
|
2388 |
|
2389 int Renderer9::getMaxSwapInterval() const |
|
2390 { |
|
2391 return mMaxSwapInterval; |
|
2392 } |
|
2393 |
|
2394 int Renderer9::getMaxSupportedSamples() const |
|
2395 { |
|
2396 return mMaxSupportedSamples; |
|
2397 } |
|
2398 |
|
2399 int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const |
|
2400 { |
|
2401 if (requested == 0) |
|
2402 { |
|
2403 return requested; |
|
2404 } |
|
2405 |
|
2406 std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format); |
|
2407 if (itr == mMultiSampleSupport.end()) |
|
2408 { |
|
2409 if (format == D3DFMT_UNKNOWN) |
|
2410 return 0; |
|
2411 return -1; |
|
2412 } |
|
2413 |
|
2414 for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i) |
|
2415 { |
|
2416 if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE) |
|
2417 { |
|
2418 return i; |
|
2419 } |
|
2420 } |
|
2421 |
|
2422 return -1; |
|
2423 } |
|
2424 |
|
2425 unsigned int Renderer9::getMaxRenderTargets() const |
|
2426 { |
|
2427 // we do not support MRT in d3d9 |
|
2428 return 1; |
|
2429 } |
|
2430 |
|
2431 D3DFORMAT Renderer9::ConvertTextureInternalFormat(GLint internalformat) |
|
2432 { |
|
2433 switch (internalformat) |
|
2434 { |
|
2435 case GL_DEPTH_COMPONENT16: |
|
2436 case GL_DEPTH_COMPONENT32_OES: |
|
2437 case GL_DEPTH24_STENCIL8_OES: |
|
2438 return D3DFMT_INTZ; |
|
2439 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: |
|
2440 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: |
|
2441 return D3DFMT_DXT1; |
|
2442 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: |
|
2443 return D3DFMT_DXT3; |
|
2444 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: |
|
2445 return D3DFMT_DXT5; |
|
2446 case GL_RGBA32F_EXT: |
|
2447 case GL_RGB32F_EXT: |
|
2448 case GL_ALPHA32F_EXT: |
|
2449 case GL_LUMINANCE32F_EXT: |
|
2450 case GL_LUMINANCE_ALPHA32F_EXT: |
|
2451 return D3DFMT_A32B32G32R32F; |
|
2452 case GL_RGBA16F_EXT: |
|
2453 case GL_RGB16F_EXT: |
|
2454 case GL_ALPHA16F_EXT: |
|
2455 case GL_LUMINANCE16F_EXT: |
|
2456 case GL_LUMINANCE_ALPHA16F_EXT: |
|
2457 return D3DFMT_A16B16G16R16F; |
|
2458 case GL_LUMINANCE8_EXT: |
|
2459 if (getLuminanceTextureSupport()) |
|
2460 { |
|
2461 return D3DFMT_L8; |
|
2462 } |
|
2463 break; |
|
2464 case GL_LUMINANCE8_ALPHA8_EXT: |
|
2465 if (getLuminanceAlphaTextureSupport()) |
|
2466 { |
|
2467 return D3DFMT_A8L8; |
|
2468 } |
|
2469 break; |
|
2470 case GL_RGB8_OES: |
|
2471 case GL_RGB565: |
|
2472 return D3DFMT_X8R8G8B8; |
|
2473 } |
|
2474 |
|
2475 return D3DFMT_A8R8G8B8; |
|
2476 } |
|
2477 |
|
2478 bool Renderer9::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source) |
|
2479 { |
|
2480 bool result = false; |
|
2481 |
|
2482 if (source && dest) |
|
2483 { |
|
2484 TextureStorage9_2D *source9 = TextureStorage9_2D::makeTextureStorage9_2D(source->getStorageInstance()); |
|
2485 TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(dest->getStorageInstance()); |
|
2486 |
|
2487 int levels = source9->levelCount(); |
|
2488 for (int i = 0; i < levels; ++i) |
|
2489 { |
|
2490 IDirect3DSurface9 *srcSurf = source9->getSurfaceLevel(i, false); |
|
2491 IDirect3DSurface9 *dstSurf = dest9->getSurfaceLevel(i, false); |
|
2492 |
|
2493 result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged()); |
|
2494 |
|
2495 if (srcSurf) srcSurf->Release(); |
|
2496 if (dstSurf) dstSurf->Release(); |
|
2497 |
|
2498 if (!result) |
|
2499 return false; |
|
2500 } |
|
2501 } |
|
2502 |
|
2503 return result; |
|
2504 } |
|
2505 |
|
2506 bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source) |
|
2507 { |
|
2508 bool result = false; |
|
2509 |
|
2510 if (source && dest) |
|
2511 { |
|
2512 TextureStorage9_Cube *source9 = TextureStorage9_Cube::makeTextureStorage9_Cube(source->getStorageInstance()); |
|
2513 TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(dest->getStorageInstance()); |
|
2514 int levels = source9->levelCount(); |
|
2515 for (int f = 0; f < 6; f++) |
|
2516 { |
|
2517 for (int i = 0; i < levels; i++) |
|
2518 { |
|
2519 IDirect3DSurface9 *srcSurf = source9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false); |
|
2520 IDirect3DSurface9 *dstSurf = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true); |
|
2521 |
|
2522 result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged()); |
|
2523 |
|
2524 if (srcSurf) srcSurf->Release(); |
|
2525 if (dstSurf) dstSurf->Release(); |
|
2526 |
|
2527 if (!result) |
|
2528 return false; |
|
2529 } |
|
2530 } |
|
2531 } |
|
2532 |
|
2533 return result; |
|
2534 } |
|
2535 |
|
2536 D3DPOOL Renderer9::getBufferPool(DWORD usage) const |
|
2537 { |
|
2538 if (mD3d9Ex != NULL) |
|
2539 { |
|
2540 return D3DPOOL_DEFAULT; |
|
2541 } |
|
2542 else |
|
2543 { |
|
2544 if (!(usage & D3DUSAGE_DYNAMIC)) |
|
2545 { |
|
2546 return D3DPOOL_MANAGED; |
|
2547 } |
|
2548 } |
|
2549 |
|
2550 return D3DPOOL_DEFAULT; |
|
2551 } |
|
2552 |
|
2553 bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, |
|
2554 GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) |
|
2555 { |
|
2556 RECT rect; |
|
2557 rect.left = sourceRect.x; |
|
2558 rect.top = sourceRect.y; |
|
2559 rect.right = sourceRect.x + sourceRect.width; |
|
2560 rect.bottom = sourceRect.y + sourceRect.height; |
|
2561 |
|
2562 return mBlit->copy(framebuffer, rect, destFormat, xoffset, yoffset, storage, level); |
|
2563 } |
|
2564 |
|
2565 bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, |
|
2566 GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) |
|
2567 { |
|
2568 RECT rect; |
|
2569 rect.left = sourceRect.x; |
|
2570 rect.top = sourceRect.y; |
|
2571 rect.right = sourceRect.x + sourceRect.width; |
|
2572 rect.bottom = sourceRect.y + sourceRect.height; |
|
2573 |
|
2574 return mBlit->copy(framebuffer, rect, destFormat, xoffset, yoffset, storage, target, level); |
|
2575 } |
|
2576 |
|
2577 bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect, |
|
2578 bool blitRenderTarget, bool blitDepthStencil) |
|
2579 { |
|
2580 endScene(); |
|
2581 |
|
2582 if (blitRenderTarget) |
|
2583 { |
|
2584 gl::Renderbuffer *readBuffer = readFramebuffer->getColorbuffer(0); |
|
2585 gl::Renderbuffer *drawBuffer = drawFramebuffer->getColorbuffer(0); |
|
2586 RenderTarget9 *readRenderTarget = NULL; |
|
2587 RenderTarget9 *drawRenderTarget = NULL; |
|
2588 IDirect3DSurface9* readSurface = NULL; |
|
2589 IDirect3DSurface9* drawSurface = NULL; |
|
2590 |
|
2591 if (readBuffer) |
|
2592 { |
|
2593 readRenderTarget = RenderTarget9::makeRenderTarget9(readBuffer->getRenderTarget()); |
|
2594 } |
|
2595 if (drawBuffer) |
|
2596 { |
|
2597 drawRenderTarget = RenderTarget9::makeRenderTarget9(drawBuffer->getRenderTarget()); |
|
2598 } |
|
2599 |
|
2600 if (readRenderTarget) |
|
2601 { |
|
2602 readSurface = readRenderTarget->getSurface(); |
|
2603 } |
|
2604 if (drawRenderTarget) |
|
2605 { |
|
2606 drawSurface = drawRenderTarget->getSurface(); |
|
2607 } |
|
2608 |
|
2609 if (!readSurface || !drawSurface) |
|
2610 { |
|
2611 ERR("Failed to retrieve the render target."); |
|
2612 return gl::error(GL_OUT_OF_MEMORY, false); |
|
2613 } |
|
2614 |
|
2615 RECT srcRect; |
|
2616 srcRect.left = readRect.x; |
|
2617 srcRect.right = readRect.x + readRect.width; |
|
2618 srcRect.top = readRect.y; |
|
2619 srcRect.bottom = readRect.y + readRect.height; |
|
2620 |
|
2621 RECT dstRect; |
|
2622 dstRect.left = drawRect.x; |
|
2623 dstRect.right = drawRect.x + drawRect.width; |
|
2624 dstRect.top = drawRect.y; |
|
2625 dstRect.bottom = drawRect.y + drawRect.height; |
|
2626 |
|
2627 HRESULT result = mDevice->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE); |
|
2628 |
|
2629 readSurface->Release(); |
|
2630 drawSurface->Release(); |
|
2631 |
|
2632 if (FAILED(result)) |
|
2633 { |
|
2634 ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); |
|
2635 return false; |
|
2636 } |
|
2637 } |
|
2638 |
|
2639 if (blitDepthStencil) |
|
2640 { |
|
2641 gl::Renderbuffer *readBuffer = readFramebuffer->getDepthOrStencilbuffer(); |
|
2642 gl::Renderbuffer *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer(); |
|
2643 RenderTarget9 *readDepthStencil = NULL; |
|
2644 RenderTarget9 *drawDepthStencil = NULL; |
|
2645 IDirect3DSurface9* readSurface = NULL; |
|
2646 IDirect3DSurface9* drawSurface = NULL; |
|
2647 |
|
2648 if (readBuffer) |
|
2649 { |
|
2650 readDepthStencil = RenderTarget9::makeRenderTarget9(readBuffer->getDepthStencil()); |
|
2651 } |
|
2652 if (drawBuffer) |
|
2653 { |
|
2654 drawDepthStencil = RenderTarget9::makeRenderTarget9(drawBuffer->getDepthStencil()); |
|
2655 } |
|
2656 |
|
2657 if (readDepthStencil) |
|
2658 { |
|
2659 readSurface = readDepthStencil->getSurface(); |
|
2660 } |
|
2661 if (drawDepthStencil) |
|
2662 { |
|
2663 drawSurface = drawDepthStencil->getSurface(); |
|
2664 } |
|
2665 |
|
2666 if (!readSurface || !drawSurface) |
|
2667 { |
|
2668 ERR("Failed to retrieve the render target."); |
|
2669 return gl::error(GL_OUT_OF_MEMORY, false); |
|
2670 } |
|
2671 |
|
2672 HRESULT result = mDevice->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE); |
|
2673 |
|
2674 readSurface->Release(); |
|
2675 drawSurface->Release(); |
|
2676 |
|
2677 if (FAILED(result)) |
|
2678 { |
|
2679 ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); |
|
2680 return false; |
|
2681 } |
|
2682 } |
|
2683 |
|
2684 return true; |
|
2685 } |
|
2686 |
|
2687 void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, |
|
2688 GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels) |
|
2689 { |
|
2690 RenderTarget9 *renderTarget = NULL; |
|
2691 IDirect3DSurface9 *surface = NULL; |
|
2692 gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0); |
|
2693 |
|
2694 if (colorbuffer) |
|
2695 { |
|
2696 renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget()); |
|
2697 } |
|
2698 |
|
2699 if (renderTarget) |
|
2700 { |
|
2701 surface = renderTarget->getSurface(); |
|
2702 } |
|
2703 |
|
2704 if (!surface) |
|
2705 { |
|
2706 // context must be lost |
|
2707 return; |
|
2708 } |
|
2709 |
|
2710 D3DSURFACE_DESC desc; |
|
2711 surface->GetDesc(&desc); |
|
2712 |
|
2713 if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) |
|
2714 { |
|
2715 UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target |
|
2716 surface->Release(); |
|
2717 return gl::error(GL_OUT_OF_MEMORY); |
|
2718 } |
|
2719 |
|
2720 HRESULT result; |
|
2721 IDirect3DSurface9 *systemSurface = NULL; |
|
2722 bool directToPixels = !packReverseRowOrder && packAlignment <= 4 && getShareHandleSupport() && |
|
2723 x == 0 && y == 0 && UINT(width) == desc.Width && UINT(height) == desc.Height && |
|
2724 desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE; |
|
2725 if (directToPixels) |
|
2726 { |
|
2727 // Use the pixels ptr as a shared handle to write directly into client's memory |
|
2728 result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, |
|
2729 D3DPOOL_SYSTEMMEM, &systemSurface, &pixels); |
|
2730 if (FAILED(result)) |
|
2731 { |
|
2732 // Try again without the shared handle |
|
2733 directToPixels = false; |
|
2734 } |
|
2735 } |
|
2736 |
|
2737 if (!directToPixels) |
|
2738 { |
|
2739 result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, |
|
2740 D3DPOOL_SYSTEMMEM, &systemSurface, NULL); |
|
2741 if (FAILED(result)) |
|
2742 { |
|
2743 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); |
|
2744 surface->Release(); |
|
2745 return gl::error(GL_OUT_OF_MEMORY); |
|
2746 } |
|
2747 } |
|
2748 |
|
2749 result = mDevice->GetRenderTargetData(surface, systemSurface); |
|
2750 surface->Release(); |
|
2751 surface = NULL; |
|
2752 |
|
2753 if (FAILED(result)) |
|
2754 { |
|
2755 systemSurface->Release(); |
|
2756 |
|
2757 // It turns out that D3D will sometimes produce more error |
|
2758 // codes than those documented. |
|
2759 if (d3d9::isDeviceLostError(result)) |
|
2760 { |
|
2761 notifyDeviceLost(); |
|
2762 return gl::error(GL_OUT_OF_MEMORY); |
|
2763 } |
|
2764 else |
|
2765 { |
|
2766 UNREACHABLE(); |
|
2767 return; |
|
2768 } |
|
2769 |
|
2770 } |
|
2771 |
|
2772 if (directToPixels) |
|
2773 { |
|
2774 systemSurface->Release(); |
|
2775 return; |
|
2776 } |
|
2777 |
|
2778 RECT rect; |
|
2779 rect.left = gl::clamp(x, 0L, static_cast<LONG>(desc.Width)); |
|
2780 rect.top = gl::clamp(y, 0L, static_cast<LONG>(desc.Height)); |
|
2781 rect.right = gl::clamp(x + width, 0L, static_cast<LONG>(desc.Width)); |
|
2782 rect.bottom = gl::clamp(y + height, 0L, static_cast<LONG>(desc.Height)); |
|
2783 |
|
2784 D3DLOCKED_RECT lock; |
|
2785 result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); |
|
2786 |
|
2787 if (FAILED(result)) |
|
2788 { |
|
2789 UNREACHABLE(); |
|
2790 systemSurface->Release(); |
|
2791 |
|
2792 return; // No sensible error to generate |
|
2793 } |
|
2794 |
|
2795 unsigned char *dest = (unsigned char*)pixels; |
|
2796 unsigned short *dest16 = (unsigned short*)pixels; |
|
2797 |
|
2798 unsigned char *source; |
|
2799 int inputPitch; |
|
2800 if (packReverseRowOrder) |
|
2801 { |
|
2802 source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); |
|
2803 inputPitch = -lock.Pitch; |
|
2804 } |
|
2805 else |
|
2806 { |
|
2807 source = (unsigned char*)lock.pBits; |
|
2808 inputPitch = lock.Pitch; |
|
2809 } |
|
2810 |
|
2811 unsigned int fastPixelSize = 0; |
|
2812 |
|
2813 if (desc.Format == D3DFMT_A8R8G8B8 && |
|
2814 format == GL_BGRA_EXT && |
|
2815 type == GL_UNSIGNED_BYTE) |
|
2816 { |
|
2817 fastPixelSize = 4; |
|
2818 } |
|
2819 else if ((desc.Format == D3DFMT_A4R4G4B4 && |
|
2820 format == GL_BGRA_EXT && |
|
2821 type == GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT) || |
|
2822 (desc.Format == D3DFMT_A1R5G5B5 && |
|
2823 format == GL_BGRA_EXT && |
|
2824 type == GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)) |
|
2825 { |
|
2826 fastPixelSize = 2; |
|
2827 } |
|
2828 else if (desc.Format == D3DFMT_A16B16G16R16F && |
|
2829 format == GL_RGBA && |
|
2830 type == GL_HALF_FLOAT_OES) |
|
2831 { |
|
2832 fastPixelSize = 8; |
|
2833 } |
|
2834 else if (desc.Format == D3DFMT_A32B32G32R32F && |
|
2835 format == GL_RGBA && |
|
2836 type == GL_FLOAT) |
|
2837 { |
|
2838 fastPixelSize = 16; |
|
2839 } |
|
2840 |
|
2841 for (int j = 0; j < rect.bottom - rect.top; j++) |
|
2842 { |
|
2843 if (fastPixelSize != 0) |
|
2844 { |
|
2845 // Fast path for formats which require no translation: |
|
2846 // D3DFMT_A8R8G8B8 to BGRA/UNSIGNED_BYTE |
|
2847 // D3DFMT_A4R4G4B4 to BGRA/UNSIGNED_SHORT_4_4_4_4_REV_EXT |
|
2848 // D3DFMT_A1R5G5B5 to BGRA/UNSIGNED_SHORT_1_5_5_5_REV_EXT |
|
2849 // D3DFMT_A16B16G16R16F to RGBA/HALF_FLOAT_OES |
|
2850 // D3DFMT_A32B32G32R32F to RGBA/FLOAT |
|
2851 // |
|
2852 // Note that buffers with no alpha go through the slow path below. |
|
2853 memcpy(dest + j * outputPitch, |
|
2854 source + j * inputPitch, |
|
2855 (rect.right - rect.left) * fastPixelSize); |
|
2856 continue; |
|
2857 } |
|
2858 else if (desc.Format == D3DFMT_A8R8G8B8 && |
|
2859 format == GL_RGBA && |
|
2860 type == GL_UNSIGNED_BYTE) |
|
2861 { |
|
2862 // Fast path for swapping red with blue |
|
2863 for (int i = 0; i < rect.right - rect.left; i++) |
|
2864 { |
|
2865 unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); |
|
2866 *(unsigned int*)(dest + 4 * i + j * outputPitch) = |
|
2867 (argb & 0xFF00FF00) | // Keep alpha and green |
|
2868 (argb & 0x00FF0000) >> 16 | // Move red to blue |
|
2869 (argb & 0x000000FF) << 16; // Move blue to red |
|
2870 } |
|
2871 continue; |
|
2872 } |
|
2873 |
|
2874 for (int i = 0; i < rect.right - rect.left; i++) |
|
2875 { |
|
2876 float r; |
|
2877 float g; |
|
2878 float b; |
|
2879 float a; |
|
2880 |
|
2881 switch (desc.Format) |
|
2882 { |
|
2883 case D3DFMT_R5G6B5: |
|
2884 { |
|
2885 unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch); |
|
2886 |
|
2887 a = 1.0f; |
|
2888 b = (rgb & 0x001F) * (1.0f / 0x001F); |
|
2889 g = (rgb & 0x07E0) * (1.0f / 0x07E0); |
|
2890 r = (rgb & 0xF800) * (1.0f / 0xF800); |
|
2891 } |
|
2892 break; |
|
2893 case D3DFMT_A1R5G5B5: |
|
2894 { |
|
2895 unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch); |
|
2896 |
|
2897 a = (argb & 0x8000) ? 1.0f : 0.0f; |
|
2898 b = (argb & 0x001F) * (1.0f / 0x001F); |
|
2899 g = (argb & 0x03E0) * (1.0f / 0x03E0); |
|
2900 r = (argb & 0x7C00) * (1.0f / 0x7C00); |
|
2901 } |
|
2902 break; |
|
2903 case D3DFMT_A8R8G8B8: |
|
2904 { |
|
2905 unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); |
|
2906 |
|
2907 a = (argb & 0xFF000000) * (1.0f / 0xFF000000); |
|
2908 b = (argb & 0x000000FF) * (1.0f / 0x000000FF); |
|
2909 g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00); |
|
2910 r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000); |
|
2911 } |
|
2912 break; |
|
2913 case D3DFMT_X8R8G8B8: |
|
2914 { |
|
2915 unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch); |
|
2916 |
|
2917 a = 1.0f; |
|
2918 b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF); |
|
2919 g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00); |
|
2920 r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000); |
|
2921 } |
|
2922 break; |
|
2923 case D3DFMT_A2R10G10B10: |
|
2924 { |
|
2925 unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); |
|
2926 |
|
2927 a = (argb & 0xC0000000) * (1.0f / 0xC0000000); |
|
2928 b = (argb & 0x000003FF) * (1.0f / 0x000003FF); |
|
2929 g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00); |
|
2930 r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000); |
|
2931 } |
|
2932 break; |
|
2933 case D3DFMT_A32B32G32R32F: |
|
2934 { |
|
2935 // float formats in D3D are stored rgba, rather than the other way round |
|
2936 r = *((float*)(source + 16 * i + j * inputPitch) + 0); |
|
2937 g = *((float*)(source + 16 * i + j * inputPitch) + 1); |
|
2938 b = *((float*)(source + 16 * i + j * inputPitch) + 2); |
|
2939 a = *((float*)(source + 16 * i + j * inputPitch) + 3); |
|
2940 } |
|
2941 break; |
|
2942 case D3DFMT_A16B16G16R16F: |
|
2943 { |
|
2944 // float formats in D3D are stored rgba, rather than the other way round |
|
2945 r = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 0)); |
|
2946 g = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 1)); |
|
2947 b = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 2)); |
|
2948 a = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 3)); |
|
2949 } |
|
2950 break; |
|
2951 default: |
|
2952 UNIMPLEMENTED(); // FIXME |
|
2953 UNREACHABLE(); |
|
2954 return; |
|
2955 } |
|
2956 |
|
2957 switch (format) |
|
2958 { |
|
2959 case GL_RGBA: |
|
2960 switch (type) |
|
2961 { |
|
2962 case GL_UNSIGNED_BYTE: |
|
2963 dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f); |
|
2964 dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); |
|
2965 dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f); |
|
2966 dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); |
|
2967 break; |
|
2968 default: UNREACHABLE(); |
|
2969 } |
|
2970 break; |
|
2971 case GL_BGRA_EXT: |
|
2972 switch (type) |
|
2973 { |
|
2974 case GL_UNSIGNED_BYTE: |
|
2975 dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f); |
|
2976 dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); |
|
2977 dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f); |
|
2978 dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); |
|
2979 break; |
|
2980 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: |
|
2981 // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section |
|
2982 // this type is packed as follows: |
|
2983 // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
|
2984 // -------------------------------------------------------------------------------- |
|
2985 // | 4th | 3rd | 2nd | 1st component | |
|
2986 // -------------------------------------------------------------------------------- |
|
2987 // in the case of BGRA_EXT, B is the first component, G the second, and so forth. |
|
2988 dest16[i + j * outputPitch / sizeof(unsigned short)] = |
|
2989 ((unsigned short)(15 * a + 0.5f) << 12)| |
|
2990 ((unsigned short)(15 * r + 0.5f) << 8) | |
|
2991 ((unsigned short)(15 * g + 0.5f) << 4) | |
|
2992 ((unsigned short)(15 * b + 0.5f) << 0); |
|
2993 break; |
|
2994 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: |
|
2995 // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section |
|
2996 // this type is packed as follows: |
|
2997 // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
|
2998 // -------------------------------------------------------------------------------- |
|
2999 // | 4th | 3rd | 2nd | 1st component | |
|
3000 // -------------------------------------------------------------------------------- |
|
3001 // in the case of BGRA_EXT, B is the first component, G the second, and so forth. |
|
3002 dest16[i + j * outputPitch / sizeof(unsigned short)] = |
|
3003 ((unsigned short)( a + 0.5f) << 15) | |
|
3004 ((unsigned short)(31 * r + 0.5f) << 10) | |
|
3005 ((unsigned short)(31 * g + 0.5f) << 5) | |
|
3006 ((unsigned short)(31 * b + 0.5f) << 0); |
|
3007 break; |
|
3008 default: UNREACHABLE(); |
|
3009 } |
|
3010 break; |
|
3011 case GL_RGB: |
|
3012 switch (type) |
|
3013 { |
|
3014 case GL_UNSIGNED_SHORT_5_6_5: |
|
3015 dest16[i + j * outputPitch / sizeof(unsigned short)] = |
|
3016 ((unsigned short)(31 * b + 0.5f) << 0) | |
|
3017 ((unsigned short)(63 * g + 0.5f) << 5) | |
|
3018 ((unsigned short)(31 * r + 0.5f) << 11); |
|
3019 break; |
|
3020 case GL_UNSIGNED_BYTE: |
|
3021 dest[3 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f); |
|
3022 dest[3 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); |
|
3023 dest[3 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f); |
|
3024 break; |
|
3025 default: UNREACHABLE(); |
|
3026 } |
|
3027 break; |
|
3028 default: UNREACHABLE(); |
|
3029 } |
|
3030 } |
|
3031 } |
|
3032 |
|
3033 systemSurface->UnlockRect(); |
|
3034 |
|
3035 systemSurface->Release(); |
|
3036 } |
|
3037 |
|
3038 RenderTarget *Renderer9::createRenderTarget(SwapChain *swapChain, bool depth) |
|
3039 { |
|
3040 SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); |
|
3041 IDirect3DSurface9 *surface = NULL; |
|
3042 if (depth) |
|
3043 { |
|
3044 surface = swapChain9->getDepthStencil(); |
|
3045 } |
|
3046 else |
|
3047 { |
|
3048 surface = swapChain9->getRenderTarget(); |
|
3049 } |
|
3050 |
|
3051 RenderTarget9 *renderTarget = new RenderTarget9(this, surface); |
|
3052 |
|
3053 return renderTarget; |
|
3054 } |
|
3055 |
|
3056 RenderTarget *Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth) |
|
3057 { |
|
3058 RenderTarget9 *renderTarget = new RenderTarget9(this, width, height, format, samples); |
|
3059 return renderTarget; |
|
3060 } |
|
3061 |
|
3062 ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type) |
|
3063 { |
|
3064 ShaderExecutable9 *executable = NULL; |
|
3065 |
|
3066 switch (type) |
|
3067 { |
|
3068 case rx::SHADER_VERTEX: |
|
3069 { |
|
3070 IDirect3DVertexShader9 *vshader = createVertexShader((DWORD*)function, length); |
|
3071 if (vshader) |
|
3072 { |
|
3073 executable = new ShaderExecutable9(function, length, vshader); |
|
3074 } |
|
3075 } |
|
3076 break; |
|
3077 case rx::SHADER_PIXEL: |
|
3078 { |
|
3079 IDirect3DPixelShader9 *pshader = createPixelShader((DWORD*)function, length); |
|
3080 if (pshader) |
|
3081 { |
|
3082 executable = new ShaderExecutable9(function, length, pshader); |
|
3083 } |
|
3084 } |
|
3085 break; |
|
3086 default: |
|
3087 UNREACHABLE(); |
|
3088 break; |
|
3089 } |
|
3090 |
|
3091 return executable; |
|
3092 } |
|
3093 |
|
3094 ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type) |
|
3095 { |
|
3096 const char *profile = NULL; |
|
3097 |
|
3098 switch (type) |
|
3099 { |
|
3100 case rx::SHADER_VERTEX: |
|
3101 profile = getMajorShaderModel() >= 3 ? "vs_3_0" : "vs_2_0"; |
|
3102 break; |
|
3103 case rx::SHADER_PIXEL: |
|
3104 profile = getMajorShaderModel() >= 3 ? "ps_3_0" : "ps_2_0"; |
|
3105 break; |
|
3106 default: |
|
3107 UNREACHABLE(); |
|
3108 return NULL; |
|
3109 } |
|
3110 |
|
3111 ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, ANGLE_COMPILE_OPTIMIZATION_LEVEL, true); |
|
3112 if (!binary) |
|
3113 return NULL; |
|
3114 |
|
3115 ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type); |
|
3116 binary->Release(); |
|
3117 |
|
3118 return executable; |
|
3119 } |
|
3120 |
|
3121 bool Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) |
|
3122 { |
|
3123 return mBlit->boxFilter(source, dest); |
|
3124 } |
|
3125 |
|
3126 D3DPOOL Renderer9::getTexturePool(DWORD usage) const |
|
3127 { |
|
3128 if (mD3d9Ex != NULL) |
|
3129 { |
|
3130 return D3DPOOL_DEFAULT; |
|
3131 } |
|
3132 else |
|
3133 { |
|
3134 if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET))) |
|
3135 { |
|
3136 return D3DPOOL_DEFAULT; |
|
3137 } |
|
3138 } |
|
3139 |
|
3140 return D3DPOOL_DEFAULT; |
|
3141 } |
|
3142 |
|
3143 bool Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) |
|
3144 { |
|
3145 if (source && dest) |
|
3146 { |
|
3147 HRESULT result = D3DERR_OUTOFVIDEOMEMORY; |
|
3148 |
|
3149 if (fromManaged) |
|
3150 { |
|
3151 D3DSURFACE_DESC desc; |
|
3152 source->GetDesc(&desc); |
|
3153 |
|
3154 IDirect3DSurface9 *surf = 0; |
|
3155 result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); |
|
3156 |
|
3157 if (SUCCEEDED(result)) |
|
3158 { |
|
3159 Image9::copyLockableSurfaces(surf, source); |
|
3160 result = mDevice->UpdateSurface(surf, NULL, dest, NULL); |
|
3161 surf->Release(); |
|
3162 } |
|
3163 } |
|
3164 else |
|
3165 { |
|
3166 endScene(); |
|
3167 result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); |
|
3168 } |
|
3169 |
|
3170 if (FAILED(result)) |
|
3171 { |
|
3172 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); |
|
3173 return false; |
|
3174 } |
|
3175 } |
|
3176 |
|
3177 return true; |
|
3178 } |
|
3179 |
|
3180 Image *Renderer9::createImage() |
|
3181 { |
|
3182 return new Image9(); |
|
3183 } |
|
3184 |
|
3185 void Renderer9::generateMipmap(Image *dest, Image *src) |
|
3186 { |
|
3187 Image9 *src9 = Image9::makeImage9(src); |
|
3188 Image9 *dst9 = Image9::makeImage9(dest); |
|
3189 Image9::generateMipmap(dst9, src9); |
|
3190 } |
|
3191 |
|
3192 TextureStorage *Renderer9::createTextureStorage2D(SwapChain *swapChain) |
|
3193 { |
|
3194 SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); |
|
3195 return new TextureStorage9_2D(this, swapChain9); |
|
3196 } |
|
3197 |
|
3198 TextureStorage *Renderer9::createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) |
|
3199 { |
|
3200 return new TextureStorage9_2D(this, levels, internalformat, usage, forceRenderable, width, height); |
|
3201 } |
|
3202 |
|
3203 TextureStorage *Renderer9::createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) |
|
3204 { |
|
3205 return new TextureStorage9_Cube(this, levels, internalformat, usage, forceRenderable, size); |
|
3206 } |
|
3207 |
|
3208 bool Renderer9::getLUID(LUID *adapterLuid) const |
|
3209 { |
|
3210 adapterLuid->HighPart = 0; |
|
3211 adapterLuid->LowPart = 0; |
|
3212 |
|
3213 if (mD3d9Ex) |
|
3214 { |
|
3215 mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid); |
|
3216 return true; |
|
3217 } |
|
3218 |
|
3219 return false; |
|
3220 } |
|
3221 |
|
3222 } |