|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "DeviceManagerD3D9.h" |
|
7 #include "LayerManagerD3D9Shaders.h" |
|
8 #include "ThebesLayerD3D9.h" |
|
9 #include "nsIServiceManager.h" |
|
10 #include "nsIConsoleService.h" |
|
11 #include "nsPrintfCString.h" |
|
12 #include "Nv3DVUtils.h" |
|
13 #include "plstr.h" |
|
14 #include <algorithm> |
|
15 #include "gfx2DGlue.h" |
|
16 #include "gfxPlatform.h" |
|
17 #include "gfxWindowsPlatform.h" |
|
18 #include "TextureD3D9.h" |
|
19 #include "mozilla/gfx/Point.h" |
|
20 |
|
21 using namespace mozilla::gfx; |
|
22 |
|
23 namespace mozilla { |
|
24 namespace layers { |
|
25 |
|
26 const LPCWSTR kClassName = L"D3D9WindowClass"; |
|
27 |
|
28 #define USE_D3D9EX |
|
29 |
|
30 struct vertex { |
|
31 float x, y; |
|
32 }; |
|
33 |
|
34 SwapChainD3D9::SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager) |
|
35 : mDeviceManager(aDeviceManager) |
|
36 , mWnd(0) |
|
37 { |
|
38 mDeviceManager->mSwapChains.AppendElement(this); |
|
39 } |
|
40 |
|
41 SwapChainD3D9::~SwapChainD3D9() |
|
42 { |
|
43 mDeviceManager->mSwapChains.RemoveElement(this); |
|
44 } |
|
45 |
|
46 bool |
|
47 SwapChainD3D9::Init(HWND hWnd) |
|
48 { |
|
49 RECT r; |
|
50 ::GetClientRect(hWnd, &r); |
|
51 |
|
52 mWnd = hWnd; |
|
53 |
|
54 D3DPRESENT_PARAMETERS pp; |
|
55 memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); |
|
56 |
|
57 pp.BackBufferFormat = D3DFMT_A8R8G8B8; |
|
58 pp.SwapEffect = D3DSWAPEFFECT_COPY; |
|
59 pp.Windowed = TRUE; |
|
60 pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; |
|
61 pp.hDeviceWindow = mWnd; |
|
62 if (r.left == r.right || r.top == r.bottom) { |
|
63 pp.BackBufferHeight = 1; |
|
64 pp.BackBufferWidth = 1; |
|
65 } |
|
66 |
|
67 HRESULT hr = mDeviceManager->device()-> |
|
68 CreateAdditionalSwapChain(&pp, |
|
69 getter_AddRefs(mSwapChain)); |
|
70 |
|
71 if (FAILED(hr)) { |
|
72 NS_WARNING("Failed to create swap chain for window."); |
|
73 return false; |
|
74 } |
|
75 |
|
76 return true; |
|
77 } |
|
78 |
|
79 already_AddRefed<IDirect3DSurface9> |
|
80 SwapChainD3D9::GetBackBuffer() |
|
81 { |
|
82 nsRefPtr<IDirect3DSurface9> backBuffer; |
|
83 mSwapChain->GetBackBuffer(0, |
|
84 D3DBACKBUFFER_TYPE_MONO, |
|
85 getter_AddRefs(backBuffer)); |
|
86 return backBuffer.forget(); |
|
87 } |
|
88 |
|
89 DeviceManagerState |
|
90 SwapChainD3D9::PrepareForRendering() |
|
91 { |
|
92 RECT r; |
|
93 if (!::GetClientRect(mWnd, &r)) { |
|
94 return DeviceFail; |
|
95 } |
|
96 |
|
97 DeviceManagerState deviceState = mDeviceManager->VerifyReadyForRendering(); |
|
98 if (deviceState != DeviceOK) { |
|
99 return deviceState; |
|
100 } |
|
101 |
|
102 if (!mSwapChain) { |
|
103 Init(mWnd); |
|
104 } |
|
105 |
|
106 if (mSwapChain) { |
|
107 nsRefPtr<IDirect3DSurface9> backBuffer = GetBackBuffer(); |
|
108 |
|
109 D3DSURFACE_DESC desc; |
|
110 backBuffer->GetDesc(&desc); |
|
111 |
|
112 if (desc.Width == r.right - r.left && desc.Height == r.bottom - r.top) { |
|
113 mDeviceManager->device()->SetRenderTarget(0, backBuffer); |
|
114 return DeviceOK; |
|
115 } |
|
116 |
|
117 mSwapChain = nullptr; |
|
118 |
|
119 Init(mWnd); |
|
120 |
|
121 if (!mSwapChain) { |
|
122 return DeviceFail; |
|
123 } |
|
124 |
|
125 backBuffer = GetBackBuffer(); |
|
126 mDeviceManager->device()->SetRenderTarget(0, backBuffer); |
|
127 |
|
128 return DeviceOK; |
|
129 } |
|
130 |
|
131 return DeviceFail; |
|
132 } |
|
133 |
|
134 void |
|
135 SwapChainD3D9::Present(const nsIntRect &aRect) |
|
136 { |
|
137 RECT r; |
|
138 r.left = aRect.x; |
|
139 r.top = aRect.y; |
|
140 r.right = aRect.XMost(); |
|
141 r.bottom = aRect.YMost(); |
|
142 |
|
143 mSwapChain->Present(&r, &r, 0, 0, 0); |
|
144 } |
|
145 |
|
146 void |
|
147 SwapChainD3D9::Present() |
|
148 { |
|
149 mSwapChain->Present(nullptr, nullptr, 0, 0, 0); |
|
150 } |
|
151 |
|
152 void |
|
153 SwapChainD3D9::Reset() |
|
154 { |
|
155 mSwapChain = nullptr; |
|
156 } |
|
157 |
|
158 #define HAS_CAP(a, b) (((a) & (b)) == (b)) |
|
159 #define LACKS_CAP(a, b) !(((a) & (b)) == (b)) |
|
160 |
|
161 uint32_t DeviceManagerD3D9::sMaskQuadRegister = 11; |
|
162 |
|
163 DeviceManagerD3D9::DeviceManagerD3D9() |
|
164 : mTextureHostList(nullptr) |
|
165 , mDeviceResetCount(0) |
|
166 , mMaxTextureSize(0) |
|
167 , mTextureAddressingMode(D3DTADDRESS_CLAMP) |
|
168 , mHasDynamicTextures(false) |
|
169 , mDeviceWasRemoved(false) |
|
170 { |
|
171 } |
|
172 |
|
173 DeviceManagerD3D9::~DeviceManagerD3D9() |
|
174 { |
|
175 DestroyDevice(); |
|
176 } |
|
177 |
|
178 bool |
|
179 DeviceManagerD3D9::Init() |
|
180 { |
|
181 WNDCLASSW wc; |
|
182 HRESULT hr; |
|
183 |
|
184 if (!GetClassInfoW(GetModuleHandle(nullptr), kClassName, &wc)) { |
|
185 ZeroMemory(&wc, sizeof(WNDCLASSW)); |
|
186 wc.hInstance = GetModuleHandle(nullptr); |
|
187 wc.lpfnWndProc = ::DefWindowProc; |
|
188 wc.lpszClassName = kClassName; |
|
189 if (!RegisterClassW(&wc)) { |
|
190 NS_WARNING("Failed to register window class for DeviceManager."); |
|
191 return false; |
|
192 } |
|
193 } |
|
194 |
|
195 mFocusWnd = ::CreateWindowW(kClassName, L"D3D9Window", WS_OVERLAPPEDWINDOW, |
|
196 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, |
|
197 nullptr, GetModuleHandle(nullptr), nullptr); |
|
198 |
|
199 if (!mFocusWnd) { |
|
200 NS_WARNING("Failed to create DeviceManagerD3D9 Window."); |
|
201 return false; |
|
202 } |
|
203 |
|
204 /* Create an Nv3DVUtils instance */ |
|
205 if (!mNv3DVUtils) { |
|
206 mNv3DVUtils = new Nv3DVUtils(); |
|
207 if (!mNv3DVUtils) { |
|
208 NS_WARNING("Could not create a new instance of Nv3DVUtils.\n"); |
|
209 } |
|
210 } |
|
211 |
|
212 /* Initialize the Nv3DVUtils object */ |
|
213 if (mNv3DVUtils) { |
|
214 mNv3DVUtils->Initialize(); |
|
215 } |
|
216 |
|
217 HMODULE d3d9 = LoadLibraryW(L"d3d9.dll"); |
|
218 decltype(Direct3DCreate9)* d3d9Create = (decltype(Direct3DCreate9)*) |
|
219 GetProcAddress(d3d9, "Direct3DCreate9"); |
|
220 decltype(Direct3DCreate9Ex)* d3d9CreateEx = (decltype(Direct3DCreate9Ex)*) |
|
221 GetProcAddress(d3d9, "Direct3DCreate9Ex"); |
|
222 |
|
223 #ifdef USE_D3D9EX |
|
224 if (d3d9CreateEx) { |
|
225 hr = d3d9CreateEx(D3D_SDK_VERSION, getter_AddRefs(mD3D9Ex)); |
|
226 if (SUCCEEDED(hr)) { |
|
227 mD3D9 = mD3D9Ex; |
|
228 } |
|
229 } |
|
230 #endif |
|
231 |
|
232 if (!mD3D9) { |
|
233 if (!d3d9Create) { |
|
234 return false; |
|
235 } |
|
236 |
|
237 mD3D9 = dont_AddRef(d3d9Create(D3D_SDK_VERSION)); |
|
238 |
|
239 if (!mD3D9) { |
|
240 return false; |
|
241 } |
|
242 } |
|
243 |
|
244 D3DADAPTER_IDENTIFIER9 ident; |
|
245 hr = mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &ident); |
|
246 |
|
247 if (FAILED(hr)) { |
|
248 return false; |
|
249 } |
|
250 |
|
251 D3DPRESENT_PARAMETERS pp; |
|
252 memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); |
|
253 |
|
254 pp.BackBufferWidth = 1; |
|
255 pp.BackBufferHeight = 1; |
|
256 pp.BackBufferFormat = D3DFMT_A8R8G8B8; |
|
257 pp.SwapEffect = D3DSWAPEFFECT_DISCARD; |
|
258 pp.Windowed = TRUE; |
|
259 pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; |
|
260 pp.hDeviceWindow = mFocusWnd; |
|
261 |
|
262 if (mD3D9Ex) { |
|
263 hr = mD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT, |
|
264 D3DDEVTYPE_HAL, |
|
265 mFocusWnd, |
|
266 D3DCREATE_FPU_PRESERVE | |
|
267 D3DCREATE_MULTITHREADED | |
|
268 D3DCREATE_MIXED_VERTEXPROCESSING, |
|
269 &pp, |
|
270 nullptr, |
|
271 getter_AddRefs(mDeviceEx)); |
|
272 if (SUCCEEDED(hr)) { |
|
273 mDevice = mDeviceEx; |
|
274 } |
|
275 |
|
276 D3DCAPS9 caps; |
|
277 if (mDeviceEx && mDeviceEx->GetDeviceCaps(&caps)) { |
|
278 if (LACKS_CAP(caps.Caps2, D3DCAPS2_DYNAMICTEXTURES)) { |
|
279 // XXX - Should we actually hit this we'll need a CanvasLayer that |
|
280 // supports static D3DPOOL_DEFAULT textures. |
|
281 NS_WARNING("D3D9Ex device not used because of lack of support for \ |
|
282 dynamic textures. This is unexpected."); |
|
283 mDevice = nullptr; |
|
284 mDeviceEx = nullptr; |
|
285 } |
|
286 } |
|
287 } |
|
288 |
|
289 if (!mDevice) { |
|
290 hr = mD3D9->CreateDevice(D3DADAPTER_DEFAULT, |
|
291 D3DDEVTYPE_HAL, |
|
292 mFocusWnd, |
|
293 D3DCREATE_FPU_PRESERVE | |
|
294 D3DCREATE_MULTITHREADED | |
|
295 D3DCREATE_MIXED_VERTEXPROCESSING, |
|
296 &pp, |
|
297 getter_AddRefs(mDevice)); |
|
298 |
|
299 if (FAILED(hr)) { |
|
300 NS_WARNING("Failed to create Device for DeviceManagerD3D9."); |
|
301 return false; |
|
302 } |
|
303 } |
|
304 |
|
305 if (!VerifyCaps()) { |
|
306 return false; |
|
307 } |
|
308 |
|
309 /* Grab the associated HMONITOR so that we can find out |
|
310 * if it changed later */ |
|
311 D3DDEVICE_CREATION_PARAMETERS parameters; |
|
312 if (FAILED(mDevice->GetCreationParameters(¶meters))) |
|
313 return false; |
|
314 mDeviceMonitor = mD3D9->GetAdapterMonitor(parameters.AdapterOrdinal); |
|
315 |
|
316 |
|
317 /* |
|
318 * Do some post device creation setup |
|
319 */ |
|
320 if (mNv3DVUtils) { |
|
321 IUnknown* devUnknown = nullptr; |
|
322 if (mDevice) { |
|
323 mDevice->QueryInterface(IID_IUnknown, (void **)&devUnknown); |
|
324 } |
|
325 mNv3DVUtils->SetDeviceInfo(devUnknown); |
|
326 } |
|
327 |
|
328 hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS, |
|
329 getter_AddRefs(mLayerVS)); |
|
330 |
|
331 if (FAILED(hr)) { |
|
332 return false; |
|
333 } |
|
334 |
|
335 hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPS, |
|
336 getter_AddRefs(mRGBPS)); |
|
337 |
|
338 if (FAILED(hr)) { |
|
339 return false; |
|
340 } |
|
341 |
|
342 hr = mDevice->CreatePixelShader((DWORD*)RGBAShaderPS, |
|
343 getter_AddRefs(mRGBAPS)); |
|
344 |
|
345 if (FAILED(hr)) { |
|
346 return false; |
|
347 } |
|
348 |
|
349 hr = mDevice->CreatePixelShader((DWORD*)ComponentPass1ShaderPS, |
|
350 getter_AddRefs(mComponentPass1PS)); |
|
351 |
|
352 if (FAILED(hr)) { |
|
353 return false; |
|
354 } |
|
355 |
|
356 hr = mDevice->CreatePixelShader((DWORD*)ComponentPass2ShaderPS, |
|
357 getter_AddRefs(mComponentPass2PS)); |
|
358 |
|
359 if (FAILED(hr)) { |
|
360 return false; |
|
361 } |
|
362 |
|
363 hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPS, |
|
364 getter_AddRefs(mYCbCrPS)); |
|
365 |
|
366 if (FAILED(hr)) { |
|
367 return false; |
|
368 } |
|
369 |
|
370 hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPS, |
|
371 getter_AddRefs(mSolidColorPS)); |
|
372 |
|
373 if (FAILED(hr)) { |
|
374 return false; |
|
375 } |
|
376 |
|
377 hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVSMask, |
|
378 getter_AddRefs(mLayerVSMask)); |
|
379 |
|
380 if (FAILED(hr)) { |
|
381 return false; |
|
382 } |
|
383 hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVSMask3D, |
|
384 getter_AddRefs(mLayerVSMask3D)); |
|
385 |
|
386 if (FAILED(hr)) { |
|
387 return false; |
|
388 } |
|
389 |
|
390 hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPSMask, |
|
391 getter_AddRefs(mRGBPSMask)); |
|
392 |
|
393 if (FAILED(hr)) { |
|
394 return false; |
|
395 } |
|
396 |
|
397 hr = mDevice->CreatePixelShader((DWORD*)RGBAShaderPSMask, |
|
398 getter_AddRefs(mRGBAPSMask)); |
|
399 |
|
400 if (FAILED(hr)) { |
|
401 return false; |
|
402 } |
|
403 |
|
404 hr = mDevice->CreatePixelShader((DWORD*)RGBAShaderPSMask3D, |
|
405 getter_AddRefs(mRGBAPSMask3D)); |
|
406 |
|
407 if (FAILED(hr)) { |
|
408 return false; |
|
409 } |
|
410 |
|
411 hr = mDevice->CreatePixelShader((DWORD*)ComponentPass1ShaderPSMask, |
|
412 getter_AddRefs(mComponentPass1PSMask)); |
|
413 |
|
414 if (FAILED(hr)) { |
|
415 return false; |
|
416 } |
|
417 |
|
418 hr = mDevice->CreatePixelShader((DWORD*)ComponentPass2ShaderPSMask, |
|
419 getter_AddRefs(mComponentPass2PSMask)); |
|
420 |
|
421 if (FAILED(hr)) { |
|
422 return false; |
|
423 } |
|
424 |
|
425 hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPSMask, |
|
426 getter_AddRefs(mYCbCrPSMask)); |
|
427 |
|
428 if (FAILED(hr)) { |
|
429 return false; |
|
430 } |
|
431 |
|
432 hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPSMask, |
|
433 getter_AddRefs(mSolidColorPSMask)); |
|
434 |
|
435 if (FAILED(hr)) { |
|
436 return false; |
|
437 } |
|
438 |
|
439 if (!CreateVertexBuffer()) { |
|
440 return false; |
|
441 } |
|
442 |
|
443 hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex)); |
|
444 if (FAILED(hr)) { |
|
445 return false; |
|
446 } |
|
447 |
|
448 D3DVERTEXELEMENT9 elements[] = { |
|
449 { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, |
|
450 D3DDECLUSAGE_POSITION, 0 }, |
|
451 D3DDECL_END() |
|
452 }; |
|
453 |
|
454 mDevice->CreateVertexDeclaration(elements, getter_AddRefs(mVD)); |
|
455 |
|
456 nsCOMPtr<nsIConsoleService> |
|
457 console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); |
|
458 |
|
459 D3DADAPTER_IDENTIFIER9 identifier; |
|
460 mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier); |
|
461 |
|
462 if (console) { |
|
463 nsString msg; |
|
464 msg += |
|
465 NS_LITERAL_STRING("Direct3D 9 DeviceManager Initialized Successfully.\nDriver: "); |
|
466 msg += NS_ConvertUTF8toUTF16( |
|
467 nsDependentCString((const char*)identifier.Driver)); |
|
468 msg += NS_LITERAL_STRING("\nDescription: "); |
|
469 msg += NS_ConvertUTF8toUTF16( |
|
470 nsDependentCString((const char*)identifier.Description)); |
|
471 msg += NS_LITERAL_STRING("\nVersion: "); |
|
472 msg += NS_ConvertUTF8toUTF16( |
|
473 nsPrintfCString("%d.%d.%d.%d", |
|
474 HIWORD(identifier.DriverVersion.HighPart), |
|
475 LOWORD(identifier.DriverVersion.HighPart), |
|
476 HIWORD(identifier.DriverVersion.LowPart), |
|
477 LOWORD(identifier.DriverVersion.LowPart))); |
|
478 console->LogStringMessage(msg.get()); |
|
479 } |
|
480 |
|
481 return true; |
|
482 } |
|
483 |
|
484 void |
|
485 DeviceManagerD3D9::SetupRenderState() |
|
486 { |
|
487 mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex)); |
|
488 mDevice->SetVertexDeclaration(mVD); |
|
489 mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); |
|
490 mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); |
|
491 mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); |
|
492 mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); |
|
493 mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); |
|
494 mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); |
|
495 mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); |
|
496 mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA); |
|
497 mDevice->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); |
|
498 mDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); |
|
499 mDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); |
|
500 mDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); |
|
501 mDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); |
|
502 mDevice->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); |
|
503 mDevice->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); |
|
504 mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, mTextureAddressingMode); |
|
505 mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, mTextureAddressingMode); |
|
506 mDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, mTextureAddressingMode); |
|
507 mDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, mTextureAddressingMode); |
|
508 mDevice->SetSamplerState(2, D3DSAMP_ADDRESSU, mTextureAddressingMode); |
|
509 mDevice->SetSamplerState(2, D3DSAMP_ADDRESSV, mTextureAddressingMode); |
|
510 } |
|
511 |
|
512 already_AddRefed<SwapChainD3D9> |
|
513 DeviceManagerD3D9::CreateSwapChain(HWND hWnd) |
|
514 { |
|
515 nsRefPtr<SwapChainD3D9> swapChain = new SwapChainD3D9(this); |
|
516 |
|
517 // See bug 604647. This line means that if we create a window while the |
|
518 // device is lost LayerManager initialization will fail, this window |
|
519 // will be permanently unaccelerated. This should be a rare situation |
|
520 // though and the need for a low-risk fix for this bug outweighs the |
|
521 // downside. |
|
522 if (VerifyReadyForRendering() != DeviceOK) { |
|
523 return nullptr; |
|
524 } |
|
525 |
|
526 if (!swapChain->Init(hWnd)) { |
|
527 return nullptr; |
|
528 } |
|
529 |
|
530 return swapChain.forget(); |
|
531 } |
|
532 |
|
533 /* |
|
534 * Finds a texture for the mask layer and sets it as an |
|
535 * input to the shaders. |
|
536 * Returns true if a texture is loaded, false if |
|
537 * a texture for the mask layer could not be loaded. |
|
538 */ |
|
539 bool |
|
540 LoadMaskTexture(Layer* aMask, IDirect3DDevice9* aDevice, |
|
541 uint32_t aMaskTexRegister) |
|
542 { |
|
543 IntSize size; |
|
544 nsRefPtr<IDirect3DTexture9> texture = |
|
545 static_cast<LayerD3D9*>(aMask->ImplData())->GetAsTexture(&size); |
|
546 |
|
547 if (!texture) { |
|
548 return false; |
|
549 } |
|
550 |
|
551 Matrix maskTransform; |
|
552 Matrix4x4 effectiveTransform = aMask->GetEffectiveTransform(); |
|
553 bool maskIs2D = effectiveTransform.CanDraw2D(&maskTransform); |
|
554 NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!"); |
|
555 Rect bounds = Rect(Point(), Size(size)); |
|
556 bounds = maskTransform.TransformBounds(bounds); |
|
557 |
|
558 aDevice->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister, |
|
559 ShaderConstantRect((float)bounds.x, |
|
560 (float)bounds.y, |
|
561 (float)bounds.width, |
|
562 (float)bounds.height), |
|
563 1); |
|
564 |
|
565 aDevice->SetTexture(aMaskTexRegister, texture); |
|
566 return true; |
|
567 } |
|
568 |
|
569 uint32_t |
|
570 DeviceManagerD3D9::SetShaderMode(ShaderMode aMode, MaskType aMaskType) |
|
571 { |
|
572 if (aMaskType == MaskNone) { |
|
573 switch (aMode) { |
|
574 case RGBLAYER: |
|
575 mDevice->SetVertexShader(mLayerVS); |
|
576 mDevice->SetPixelShader(mRGBPS); |
|
577 break; |
|
578 case RGBALAYER: |
|
579 mDevice->SetVertexShader(mLayerVS); |
|
580 mDevice->SetPixelShader(mRGBAPS); |
|
581 break; |
|
582 case COMPONENTLAYERPASS1: |
|
583 mDevice->SetVertexShader(mLayerVS); |
|
584 mDevice->SetPixelShader(mComponentPass1PS); |
|
585 break; |
|
586 case COMPONENTLAYERPASS2: |
|
587 mDevice->SetVertexShader(mLayerVS); |
|
588 mDevice->SetPixelShader(mComponentPass2PS); |
|
589 break; |
|
590 case YCBCRLAYER: |
|
591 mDevice->SetVertexShader(mLayerVS); |
|
592 mDevice->SetPixelShader(mYCbCrPS); |
|
593 break; |
|
594 case SOLIDCOLORLAYER: |
|
595 mDevice->SetVertexShader(mLayerVS); |
|
596 mDevice->SetPixelShader(mSolidColorPS); |
|
597 break; |
|
598 } |
|
599 return 0; |
|
600 } |
|
601 |
|
602 uint32_t maskTexRegister; |
|
603 switch (aMode) { |
|
604 case RGBLAYER: |
|
605 mDevice->SetVertexShader(mLayerVSMask); |
|
606 mDevice->SetPixelShader(mRGBPSMask); |
|
607 maskTexRegister = 1; |
|
608 break; |
|
609 case RGBALAYER: |
|
610 if (aMaskType == Mask2d) { |
|
611 mDevice->SetVertexShader(mLayerVSMask); |
|
612 mDevice->SetPixelShader(mRGBAPSMask); |
|
613 } else { |
|
614 mDevice->SetVertexShader(mLayerVSMask3D); |
|
615 mDevice->SetPixelShader(mRGBAPSMask3D); |
|
616 } |
|
617 maskTexRegister = 1; |
|
618 break; |
|
619 case COMPONENTLAYERPASS1: |
|
620 mDevice->SetVertexShader(mLayerVSMask); |
|
621 mDevice->SetPixelShader(mComponentPass1PSMask); |
|
622 maskTexRegister = 2; |
|
623 break; |
|
624 case COMPONENTLAYERPASS2: |
|
625 mDevice->SetVertexShader(mLayerVSMask); |
|
626 mDevice->SetPixelShader(mComponentPass2PSMask); |
|
627 maskTexRegister = 2; |
|
628 break; |
|
629 case YCBCRLAYER: |
|
630 mDevice->SetVertexShader(mLayerVSMask); |
|
631 mDevice->SetPixelShader(mYCbCrPSMask); |
|
632 maskTexRegister = 3; |
|
633 break; |
|
634 case SOLIDCOLORLAYER: |
|
635 mDevice->SetVertexShader(mLayerVSMask); |
|
636 mDevice->SetPixelShader(mSolidColorPSMask); |
|
637 maskTexRegister = 0; |
|
638 break; |
|
639 } |
|
640 return maskTexRegister; |
|
641 } |
|
642 |
|
643 void |
|
644 DeviceManagerD3D9::SetShaderMode(ShaderMode aMode, Layer* aMask, bool aIs2D) |
|
645 { |
|
646 MaskType maskType = MaskNone; |
|
647 if (aMask) { |
|
648 maskType = aIs2D ? Mask2d : Mask3d; |
|
649 } |
|
650 uint32_t maskTexRegister = SetShaderMode(aMode, maskType); |
|
651 if (aMask) { |
|
652 // register allocations are taken from LayerManagerD3D9Shaders.h after |
|
653 // the shaders are compiled (genshaders.sh) |
|
654 if (!LoadMaskTexture(aMask, mDevice, maskTexRegister)) { |
|
655 // if we can't load the mask, fall back to unmasked rendering |
|
656 NS_WARNING("Could not load texture for mask layer."); |
|
657 SetShaderMode(aMode, MaskNone); |
|
658 } |
|
659 } |
|
660 } |
|
661 |
|
662 void |
|
663 DeviceManagerD3D9::DestroyDevice() |
|
664 { |
|
665 ++mDeviceResetCount; |
|
666 mDeviceWasRemoved = true; |
|
667 if (!IsD3D9Ex()) { |
|
668 ReleaseTextureResources(); |
|
669 } |
|
670 gfxWindowsPlatform::GetPlatform()->OnDeviceManagerDestroy(this); |
|
671 } |
|
672 |
|
673 DeviceManagerState |
|
674 DeviceManagerD3D9::VerifyReadyForRendering() |
|
675 { |
|
676 if (mDeviceWasRemoved) { |
|
677 return DeviceMustRecreate; |
|
678 } |
|
679 |
|
680 HRESULT hr = mDevice->TestCooperativeLevel(); |
|
681 |
|
682 if (SUCCEEDED(hr)) { |
|
683 if (IsD3D9Ex()) { |
|
684 hr = mDeviceEx->CheckDeviceState(mFocusWnd); |
|
685 |
|
686 if (FAILED(hr)) { |
|
687 DestroyDevice(); |
|
688 return DeviceMustRecreate; |
|
689 } |
|
690 } |
|
691 return DeviceOK; |
|
692 } |
|
693 |
|
694 // We need to release all texture resources and swap chains before resetting. |
|
695 for (unsigned int i = 0; i < mLayersWithResources.Length(); i++) { |
|
696 mLayersWithResources[i]->CleanResources(); |
|
697 } |
|
698 ReleaseTextureResources(); |
|
699 for (unsigned int i = 0; i < mSwapChains.Length(); i++) { |
|
700 mSwapChains[i]->Reset(); |
|
701 } |
|
702 |
|
703 mVB = nullptr; |
|
704 |
|
705 D3DPRESENT_PARAMETERS pp; |
|
706 memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); |
|
707 |
|
708 pp.BackBufferWidth = 1; |
|
709 pp.BackBufferHeight = 1; |
|
710 pp.BackBufferFormat = D3DFMT_A8R8G8B8; |
|
711 pp.SwapEffect = D3DSWAPEFFECT_DISCARD; |
|
712 pp.Windowed = TRUE; |
|
713 pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; |
|
714 pp.hDeviceWindow = mFocusWnd; |
|
715 |
|
716 // Whatever happens from now on, either we reset the device, or we should |
|
717 // pretend we reset the device so that the layer manager or compositor |
|
718 // doesn't ignore it. |
|
719 ++mDeviceResetCount; |
|
720 |
|
721 // if we got this far, we know !SUCCEEDEED(hr), that means hr is one of |
|
722 // D3DERR_DEVICELOST, D3DERR_DEVICENOTRESET, D3DERR_DRIVERINTERNALERROR. |
|
723 // It is only worth resetting if we get D3DERR_DEVICENOTRESET. If we get |
|
724 // D3DERR_DEVICELOST we can wait and see if we get D3DERR_DEVICENOTRESET |
|
725 // later, then reset. |
|
726 if (hr == D3DERR_DEVICELOST) { |
|
727 HMONITOR hMonitorWindow; |
|
728 hMonitorWindow = MonitorFromWindow(mFocusWnd, MONITOR_DEFAULTTOPRIMARY); |
|
729 if (hMonitorWindow != mDeviceMonitor) { |
|
730 /* jrmuizel: I'm not sure how to trigger this case. Usually, we get |
|
731 * DEVICENOTRESET right away and Reset() succeeds without going through a |
|
732 * set of DEVICELOSTs. This is presumeably because we don't call |
|
733 * VerifyReadyForRendering when we don't have any reason to paint. |
|
734 * Hopefully comparing HMONITORs is not overly aggressive. |
|
735 * See bug 626678. |
|
736 */ |
|
737 /* The monitor has changed. We have to assume that the |
|
738 * DEVICENOTRESET will not be coming. */ |
|
739 DestroyDevice(); |
|
740 return DeviceMustRecreate; |
|
741 } |
|
742 return DeviceFail; |
|
743 } |
|
744 if (hr == D3DERR_DEVICENOTRESET) { |
|
745 hr = mDevice->Reset(&pp); |
|
746 } |
|
747 |
|
748 if (FAILED(hr) || !CreateVertexBuffer()) { |
|
749 DestroyDevice(); |
|
750 return DeviceMustRecreate; |
|
751 } |
|
752 |
|
753 return DeviceOK; |
|
754 } |
|
755 |
|
756 bool |
|
757 DeviceManagerD3D9::VerifyCaps() |
|
758 { |
|
759 D3DCAPS9 caps; |
|
760 HRESULT hr = mDevice->GetDeviceCaps(&caps); |
|
761 |
|
762 if (FAILED(hr)) { |
|
763 return false; |
|
764 } |
|
765 |
|
766 if (LACKS_CAP(caps.DevCaps, D3DDEVCAPS_TEXTUREVIDEOMEMORY)) { |
|
767 return false; |
|
768 } |
|
769 |
|
770 if (LACKS_CAP(caps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE)) { |
|
771 return false; |
|
772 } |
|
773 |
|
774 if (LACKS_CAP(caps.SrcBlendCaps, D3DPBLENDCAPS_ONE) || |
|
775 LACKS_CAP(caps.SrcBlendCaps, D3DBLEND_SRCALPHA) || |
|
776 LACKS_CAP(caps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA)) { |
|
777 return false; |
|
778 } |
|
779 |
|
780 if (LACKS_CAP(caps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST)) { |
|
781 return false; |
|
782 } |
|
783 |
|
784 if (LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_ALPHA) || |
|
785 HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_SQUAREONLY) || |
|
786 (HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_POW2) && |
|
787 LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL))) { |
|
788 return false; |
|
789 } |
|
790 |
|
791 if (LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MAGFLINEAR) || |
|
792 LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MINFLINEAR)) { |
|
793 return false; |
|
794 } |
|
795 |
|
796 if (LACKS_CAP(caps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP)) { |
|
797 return false; |
|
798 } |
|
799 |
|
800 if (caps.MaxTextureHeight < 4096 || |
|
801 caps.MaxTextureWidth < 4096) { |
|
802 return false; |
|
803 } |
|
804 mMaxTextureSize = std::min(caps.MaxTextureHeight, caps.MaxTextureWidth); |
|
805 |
|
806 if ((caps.PixelShaderVersion & 0xffff) < 0x200 || |
|
807 (caps.VertexShaderVersion & 0xffff) < 0x200) { |
|
808 return false; |
|
809 } |
|
810 |
|
811 if (HAS_CAP(caps.Caps2, D3DCAPS2_DYNAMICTEXTURES)) { |
|
812 mHasDynamicTextures = true; |
|
813 } |
|
814 |
|
815 if (HAS_CAP(caps.TextureAddressCaps, D3DPTADDRESSCAPS_WRAP) && |
|
816 LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) { |
|
817 mTextureAddressingMode = D3DTADDRESS_WRAP; |
|
818 } else { |
|
819 gfxPlatform::DisableBufferRotation(); |
|
820 } |
|
821 |
|
822 return true; |
|
823 } |
|
824 |
|
825 bool |
|
826 DeviceManagerD3D9::CreateVertexBuffer() |
|
827 { |
|
828 HRESULT hr; |
|
829 |
|
830 hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4, |
|
831 D3DUSAGE_WRITEONLY, |
|
832 0, |
|
833 D3DPOOL_DEFAULT, |
|
834 getter_AddRefs(mVB), |
|
835 nullptr); |
|
836 |
|
837 if (FAILED(hr)) { |
|
838 return false; |
|
839 } |
|
840 |
|
841 vertex *vertices; |
|
842 hr = mVB->Lock(0, 0, (void**)&vertices, 0); |
|
843 if (FAILED(hr)) { |
|
844 return false; |
|
845 } |
|
846 |
|
847 vertices[0].x = vertices[0].y = 0; |
|
848 vertices[1].x = 1; vertices[1].y = 0; |
|
849 vertices[2].x = 0; vertices[2].y = 1; |
|
850 vertices[3].x = 1; vertices[3].y = 1; |
|
851 |
|
852 mVB->Unlock(); |
|
853 |
|
854 return true; |
|
855 } |
|
856 |
|
857 TemporaryRef<IDirect3DTexture9> |
|
858 DeviceManagerD3D9::CreateTexture(const IntSize &aSize, |
|
859 _D3DFORMAT aFormat, |
|
860 D3DPOOL aPool, |
|
861 TextureSourceD3D9* aTextureHost) |
|
862 { |
|
863 if (mDeviceWasRemoved) { |
|
864 return nullptr; |
|
865 } |
|
866 RefPtr<IDirect3DTexture9> result; |
|
867 if (FAILED(device()->CreateTexture(aSize.width, aSize.height, |
|
868 1, 0, aFormat, aPool, |
|
869 byRef(result), nullptr))) { |
|
870 return nullptr; |
|
871 } |
|
872 |
|
873 NS_ASSERTION(aPool != D3DPOOL_MANAGED, |
|
874 "Should not be using MANAGED texture pool. We will get an error when we have to recreate the device"); |
|
875 if (aPool == D3DPOOL_DEFAULT) { |
|
876 MOZ_ASSERT(aTextureHost, "We need a texture host to track so we can release the texture."); |
|
877 RegisterTextureHost(aTextureHost); |
|
878 } |
|
879 |
|
880 return result; |
|
881 } |
|
882 |
|
883 #ifdef DEBUG |
|
884 bool |
|
885 DeviceManagerD3D9::IsInTextureHostList(TextureSourceD3D9* aFind) |
|
886 { |
|
887 TextureSourceD3D9* cur = mTextureHostList; |
|
888 while(cur) { |
|
889 if (cur == aFind) { |
|
890 return true; |
|
891 } |
|
892 cur = cur->mNextHost; |
|
893 } |
|
894 |
|
895 return false; |
|
896 } |
|
897 #endif |
|
898 |
|
899 void |
|
900 DeviceManagerD3D9::RegisterTextureHost(TextureSourceD3D9* aHost) |
|
901 { |
|
902 if (!aHost) { |
|
903 return; |
|
904 } |
|
905 |
|
906 // Don't add aHost to the list twice. |
|
907 if (aHost->mPreviousHost || |
|
908 mTextureHostList == aHost) { |
|
909 MOZ_ASSERT(IsInTextureHostList(aHost)); |
|
910 return; |
|
911 } |
|
912 |
|
913 MOZ_ASSERT(!aHost->mNextHost); |
|
914 MOZ_ASSERT(!IsInTextureHostList(aHost)); |
|
915 |
|
916 if (mTextureHostList) { |
|
917 MOZ_ASSERT(!mTextureHostList->mPreviousHost); |
|
918 mTextureHostList->mPreviousHost = aHost; |
|
919 aHost->mNextHost = mTextureHostList; |
|
920 } |
|
921 mTextureHostList = aHost; |
|
922 MOZ_ASSERT(!aHost->mCreatingDeviceManager, "Already created texture?"); |
|
923 MOZ_ASSERT(IsInTextureHostList(aHost)); |
|
924 aHost->mCreatingDeviceManager = this; |
|
925 } |
|
926 |
|
927 void |
|
928 DeviceManagerD3D9::ReleaseTextureResources() |
|
929 { |
|
930 TextureSourceD3D9* host = mTextureHostList; |
|
931 while (host) { |
|
932 host->ReleaseTextureResources(); |
|
933 TextureSourceD3D9* oldHost = host; |
|
934 host = oldHost->mNextHost; |
|
935 oldHost->mPreviousHost = nullptr; |
|
936 oldHost->mNextHost = nullptr; |
|
937 oldHost->mCreatingDeviceManager = nullptr; |
|
938 } |
|
939 mTextureHostList = nullptr; |
|
940 } |
|
941 |
|
942 void |
|
943 DeviceManagerD3D9::RemoveTextureListHead(TextureSourceD3D9* aHost) |
|
944 { |
|
945 MOZ_ASSERT(!aHost->mCreatingDeviceManager || aHost->mCreatingDeviceManager == this, |
|
946 "Wrong device manager"); |
|
947 MOZ_ASSERT(aHost && mTextureHostList == aHost, |
|
948 "aHost is not the head of the texture host list"); |
|
949 mTextureHostList = aHost->mNextHost; |
|
950 } |
|
951 |
|
952 } /* namespace layers */ |
|
953 } /* namespace mozilla */ |