|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
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 "CompositorD3D9.h" |
|
7 #include "LayerManagerD3D9Shaders.h" |
|
8 #include "gfxWindowsPlatform.h" |
|
9 #include "nsIWidget.h" |
|
10 #include "mozilla/layers/ImageHost.h" |
|
11 #include "mozilla/layers/ContentHost.h" |
|
12 #include "mozilla/layers/Effects.h" |
|
13 #include "nsWindowsHelpers.h" |
|
14 #include "Nv3DVUtils.h" |
|
15 #include "gfxFailure.h" |
|
16 #include "mozilla/layers/PCompositorParent.h" |
|
17 #include "mozilla/layers/LayerManagerComposite.h" |
|
18 #include "gfxPrefs.h" |
|
19 |
|
20 using namespace mozilla::gfx; |
|
21 |
|
22 namespace mozilla { |
|
23 namespace layers { |
|
24 |
|
25 CompositorD3D9::CompositorD3D9(PCompositorParent* aParent, nsIWidget *aWidget) |
|
26 : Compositor(aParent) |
|
27 , mWidget(aWidget) |
|
28 , mDeviceResetCount(0) |
|
29 { |
|
30 Compositor::SetBackend(LayersBackend::LAYERS_D3D9); |
|
31 } |
|
32 |
|
33 CompositorD3D9::~CompositorD3D9() |
|
34 { |
|
35 mSwapChain = nullptr; |
|
36 mDeviceManager = nullptr; |
|
37 } |
|
38 |
|
39 bool |
|
40 CompositorD3D9::Initialize() |
|
41 { |
|
42 if (!gfxPlatform::CanUseDirect3D9()) { |
|
43 NS_WARNING("Direct3D 9-accelerated layers are not supported on this system."); |
|
44 return false; |
|
45 } |
|
46 |
|
47 mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); |
|
48 if (!mDeviceManager) { |
|
49 return false; |
|
50 } |
|
51 |
|
52 mSwapChain = mDeviceManager-> |
|
53 CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW)); |
|
54 |
|
55 if (!mSwapChain) { |
|
56 return false; |
|
57 } |
|
58 |
|
59 return true; |
|
60 } |
|
61 |
|
62 TextureFactoryIdentifier |
|
63 CompositorD3D9::GetTextureFactoryIdentifier() |
|
64 { |
|
65 TextureFactoryIdentifier ident; |
|
66 ident.mMaxTextureSize = GetMaxTextureSize(); |
|
67 ident.mParentBackend = LayersBackend::LAYERS_D3D9; |
|
68 ident.mParentProcessId = XRE_GetProcessType(); |
|
69 return ident; |
|
70 } |
|
71 |
|
72 bool |
|
73 CompositorD3D9::CanUseCanvasLayerForSize(const IntSize &aSize) |
|
74 { |
|
75 int32_t maxTextureSize = GetMaxTextureSize(); |
|
76 |
|
77 if (aSize.width > maxTextureSize || aSize.height > maxTextureSize) { |
|
78 return false; |
|
79 } |
|
80 |
|
81 return true; |
|
82 } |
|
83 |
|
84 int32_t |
|
85 CompositorD3D9::GetMaxTextureSize() const |
|
86 { |
|
87 return mDeviceManager ? mDeviceManager->GetMaxTextureSize() : INT32_MAX; |
|
88 } |
|
89 |
|
90 TemporaryRef<DataTextureSource> |
|
91 CompositorD3D9::CreateDataTextureSource(TextureFlags aFlags) |
|
92 { |
|
93 return new DataTextureSourceD3D9(SurfaceFormat::UNKNOWN, this, aFlags); |
|
94 } |
|
95 |
|
96 TemporaryRef<CompositingRenderTarget> |
|
97 CompositorD3D9::CreateRenderTarget(const gfx::IntRect &aRect, |
|
98 SurfaceInitMode aInit) |
|
99 { |
|
100 if (!mDeviceManager) { |
|
101 return nullptr; |
|
102 } |
|
103 |
|
104 RefPtr<IDirect3DTexture9> texture; |
|
105 HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1, |
|
106 D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, |
|
107 D3DPOOL_DEFAULT, byRef(texture), |
|
108 nullptr); |
|
109 if (FAILED(hr)) { |
|
110 ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTarget: Failed to create texture"), |
|
111 hr); |
|
112 return nullptr; |
|
113 } |
|
114 |
|
115 RefPtr<CompositingRenderTargetD3D9> rt = |
|
116 new CompositingRenderTargetD3D9(texture, aInit, aRect); |
|
117 |
|
118 return rt; |
|
119 } |
|
120 |
|
121 TemporaryRef<CompositingRenderTarget> |
|
122 CompositorD3D9::CreateRenderTargetFromSource(const gfx::IntRect &aRect, |
|
123 const CompositingRenderTarget *aSource, |
|
124 const gfx::IntPoint &aSourcePoint) |
|
125 { |
|
126 if (!mDeviceManager) { |
|
127 return nullptr; |
|
128 } |
|
129 |
|
130 RefPtr<IDirect3DTexture9> texture; |
|
131 HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1, |
|
132 D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, |
|
133 D3DPOOL_DEFAULT, byRef(texture), |
|
134 nullptr); |
|
135 if (FAILED(hr)) { |
|
136 ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to create texture"), |
|
137 hr); |
|
138 return nullptr; |
|
139 } |
|
140 |
|
141 if (aSource) { |
|
142 nsRefPtr<IDirect3DSurface9> sourceSurface = |
|
143 static_cast<const CompositingRenderTargetD3D9*>(aSource)->GetD3D9Surface(); |
|
144 |
|
145 nsRefPtr<IDirect3DSurface9> destSurface; |
|
146 hr = texture->GetSurfaceLevel(0, getter_AddRefs(destSurface)); |
|
147 if (FAILED(hr)) { |
|
148 NS_WARNING("Failed to get texture surface level for dest."); |
|
149 } |
|
150 |
|
151 if (sourceSurface && destSurface) { |
|
152 RECT sourceRect; |
|
153 sourceRect.left = aSourcePoint.x; |
|
154 sourceRect.right = aSourcePoint.x + aRect.width; |
|
155 sourceRect.top = aSourcePoint.y; |
|
156 sourceRect.bottom = aSourcePoint.y + aRect.height; |
|
157 RECT destRect; |
|
158 destRect.left = 0; |
|
159 destRect.right = aRect.width; |
|
160 destRect.top = 0; |
|
161 destRect.bottom = aRect.height; |
|
162 |
|
163 // copy the source to the dest |
|
164 hr = device()->StretchRect(sourceSurface, |
|
165 &sourceRect, |
|
166 destSurface, |
|
167 &destRect, |
|
168 D3DTEXF_NONE); |
|
169 if (FAILED(hr)) { |
|
170 ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to update texture"), |
|
171 hr); |
|
172 } |
|
173 } |
|
174 } |
|
175 |
|
176 RefPtr<CompositingRenderTargetD3D9> rt = |
|
177 new CompositingRenderTargetD3D9(texture, |
|
178 INIT_MODE_NONE, |
|
179 aRect); |
|
180 |
|
181 return rt; |
|
182 } |
|
183 |
|
184 void |
|
185 CompositorD3D9::SetRenderTarget(CompositingRenderTarget *aRenderTarget) |
|
186 { |
|
187 MOZ_ASSERT(aRenderTarget && mDeviceManager); |
|
188 RefPtr<CompositingRenderTargetD3D9> oldRT = mCurrentRT; |
|
189 mCurrentRT = static_cast<CompositingRenderTargetD3D9*>(aRenderTarget); |
|
190 mCurrentRT->BindRenderTarget(device()); |
|
191 PrepareViewport(mCurrentRT->GetSize(), Matrix()); |
|
192 } |
|
193 |
|
194 static DeviceManagerD3D9::ShaderMode |
|
195 ShaderModeForEffectType(EffectTypes aEffectType, gfx::SurfaceFormat aFormat) |
|
196 { |
|
197 switch (aEffectType) { |
|
198 case EFFECT_SOLID_COLOR: |
|
199 return DeviceManagerD3D9::SOLIDCOLORLAYER; |
|
200 case EFFECT_RENDER_TARGET: |
|
201 return DeviceManagerD3D9::RGBALAYER; |
|
202 case EFFECT_RGB: |
|
203 if (aFormat == SurfaceFormat::B8G8R8A8 || aFormat == SurfaceFormat::R8G8B8A8) |
|
204 return DeviceManagerD3D9::RGBALAYER; |
|
205 return DeviceManagerD3D9::RGBLAYER; |
|
206 case EFFECT_YCBCR: |
|
207 return DeviceManagerD3D9::YCBCRLAYER; |
|
208 } |
|
209 |
|
210 MOZ_CRASH("Bad effect type"); |
|
211 } |
|
212 |
|
213 void |
|
214 CompositorD3D9::ClearRect(const gfx::Rect& aRect) |
|
215 { |
|
216 D3DRECT rect; |
|
217 rect.x1 = aRect.X(); |
|
218 rect.y1 = aRect.Y(); |
|
219 rect.x2 = aRect.XMost(); |
|
220 rect.y2 = aRect.YMost(); |
|
221 |
|
222 device()->Clear(1, &rect, D3DCLEAR_TARGET, |
|
223 0x00000000, 0, 0); |
|
224 } |
|
225 |
|
226 void |
|
227 CompositorD3D9::DrawQuad(const gfx::Rect &aRect, |
|
228 const gfx::Rect &aClipRect, |
|
229 const EffectChain &aEffectChain, |
|
230 gfx::Float aOpacity, |
|
231 const gfx::Matrix4x4 &aTransform) |
|
232 { |
|
233 if (!mDeviceManager) { |
|
234 return; |
|
235 } |
|
236 |
|
237 IDirect3DDevice9* d3d9Device = device(); |
|
238 MOZ_ASSERT(d3d9Device, "We should be able to get a device now"); |
|
239 |
|
240 MOZ_ASSERT(mCurrentRT, "No render target"); |
|
241 d3d9Device->SetVertexShaderConstantF(CBmLayerTransform, &aTransform._11, 4); |
|
242 |
|
243 IntPoint origin = mCurrentRT->GetOrigin(); |
|
244 float renderTargetOffset[] = { origin.x, origin.y, 0, 0 }; |
|
245 d3d9Device->SetVertexShaderConstantF(CBvRenderTargetOffset, |
|
246 renderTargetOffset, |
|
247 1); |
|
248 d3d9Device->SetVertexShaderConstantF(CBvLayerQuad, |
|
249 ShaderConstantRect(aRect.x, |
|
250 aRect.y, |
|
251 aRect.width, |
|
252 aRect.height), |
|
253 1); |
|
254 bool target = false; |
|
255 |
|
256 if (aEffectChain.mPrimaryEffect->mType != EFFECT_SOLID_COLOR) { |
|
257 float opacity[4]; |
|
258 /* |
|
259 * We always upload a 4 component float, but the shader will use only the |
|
260 * first component since it's declared as a 'float'. |
|
261 */ |
|
262 opacity[0] = aOpacity; |
|
263 d3d9Device->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1); |
|
264 } |
|
265 |
|
266 bool isPremultiplied = true; |
|
267 |
|
268 MaskType maskType = MaskNone; |
|
269 |
|
270 if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) { |
|
271 if (aTransform.Is2D()) { |
|
272 maskType = Mask2d; |
|
273 } else { |
|
274 maskType = Mask3d; |
|
275 } |
|
276 } |
|
277 |
|
278 RECT scissor; |
|
279 scissor.left = aClipRect.x; |
|
280 scissor.right = aClipRect.XMost(); |
|
281 scissor.top = aClipRect.y; |
|
282 scissor.bottom = aClipRect.YMost(); |
|
283 d3d9Device->SetScissorRect(&scissor); |
|
284 |
|
285 uint32_t maskTexture = 0; |
|
286 switch (aEffectChain.mPrimaryEffect->mType) { |
|
287 case EFFECT_SOLID_COLOR: |
|
288 { |
|
289 // output color is premultiplied, so we need to adjust all channels. |
|
290 Color layerColor = |
|
291 static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor; |
|
292 float color[4]; |
|
293 color[0] = layerColor.r * layerColor.a * aOpacity; |
|
294 color[1] = layerColor.g * layerColor.a * aOpacity; |
|
295 color[2] = layerColor.b * layerColor.a * aOpacity; |
|
296 color[3] = layerColor.a * aOpacity; |
|
297 |
|
298 d3d9Device->SetPixelShaderConstantF(CBvColor, color, 1); |
|
299 |
|
300 maskTexture = mDeviceManager |
|
301 ->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER, maskType); |
|
302 } |
|
303 break; |
|
304 case EFFECT_RENDER_TARGET: |
|
305 case EFFECT_RGB: |
|
306 { |
|
307 TexturedEffect* texturedEffect = |
|
308 static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); |
|
309 |
|
310 Rect textureCoords = texturedEffect->mTextureCoords; |
|
311 d3d9Device->SetVertexShaderConstantF(CBvTextureCoords, |
|
312 ShaderConstantRect( |
|
313 textureCoords.x, |
|
314 textureCoords.y, |
|
315 textureCoords.width, |
|
316 textureCoords.height), |
|
317 1); |
|
318 |
|
319 SetSamplerForFilter(texturedEffect->mFilter); |
|
320 |
|
321 TextureSourceD3D9* source = texturedEffect->mTexture->AsSourceD3D9(); |
|
322 d3d9Device->SetTexture(0, source->GetD3D9Texture()); |
|
323 |
|
324 maskTexture = mDeviceManager |
|
325 ->SetShaderMode(ShaderModeForEffectType(aEffectChain.mPrimaryEffect->mType, |
|
326 texturedEffect->mTexture->GetFormat()), |
|
327 maskType); |
|
328 |
|
329 isPremultiplied = texturedEffect->mPremultiplied; |
|
330 } |
|
331 break; |
|
332 case EFFECT_YCBCR: |
|
333 { |
|
334 EffectYCbCr* ycbcrEffect = |
|
335 static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get()); |
|
336 |
|
337 SetSamplerForFilter(Filter::LINEAR); |
|
338 |
|
339 Rect textureCoords = ycbcrEffect->mTextureCoords; |
|
340 d3d9Device->SetVertexShaderConstantF(CBvTextureCoords, |
|
341 ShaderConstantRect( |
|
342 textureCoords.x, |
|
343 textureCoords.y, |
|
344 textureCoords.width, |
|
345 textureCoords.height), |
|
346 1); |
|
347 |
|
348 const int Y = 0, Cb = 1, Cr = 2; |
|
349 TextureSource* source = ycbcrEffect->mTexture; |
|
350 |
|
351 if (!source) { |
|
352 NS_WARNING("No texture to composite"); |
|
353 return; |
|
354 } |
|
355 |
|
356 if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) || !source->GetSubSource(Cr)) { |
|
357 // This can happen if we failed to upload the textures, most likely |
|
358 // because of unsupported dimensions (we don't tile YCbCr textures). |
|
359 return; |
|
360 } |
|
361 |
|
362 TextureSourceD3D9* sourceY = source->GetSubSource(Y)->AsSourceD3D9(); |
|
363 TextureSourceD3D9* sourceCb = source->GetSubSource(Cb)->AsSourceD3D9(); |
|
364 TextureSourceD3D9* sourceCr = source->GetSubSource(Cr)->AsSourceD3D9(); |
|
365 |
|
366 |
|
367 MOZ_ASSERT(sourceY->GetD3D9Texture()); |
|
368 MOZ_ASSERT(sourceCb->GetD3D9Texture()); |
|
369 MOZ_ASSERT(sourceCr->GetD3D9Texture()); |
|
370 |
|
371 /* |
|
372 * Send 3d control data and metadata |
|
373 */ |
|
374 if (mDeviceManager->GetNv3DVUtils()) { |
|
375 Nv_Stereo_Mode mode; |
|
376 switch (source->AsSourceD3D9()->GetStereoMode()) { |
|
377 case StereoMode::LEFT_RIGHT: |
|
378 mode = NV_STEREO_MODE_LEFT_RIGHT; |
|
379 break; |
|
380 case StereoMode::RIGHT_LEFT: |
|
381 mode = NV_STEREO_MODE_RIGHT_LEFT; |
|
382 break; |
|
383 case StereoMode::BOTTOM_TOP: |
|
384 mode = NV_STEREO_MODE_BOTTOM_TOP; |
|
385 break; |
|
386 case StereoMode::TOP_BOTTOM: |
|
387 mode = NV_STEREO_MODE_TOP_BOTTOM; |
|
388 break; |
|
389 case StereoMode::MONO: |
|
390 mode = NV_STEREO_MODE_MONO; |
|
391 break; |
|
392 } |
|
393 |
|
394 // Send control data even in mono case so driver knows to leave stereo mode. |
|
395 mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE); |
|
396 |
|
397 if (source->AsSourceD3D9()->GetStereoMode() != StereoMode::MONO) { |
|
398 mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE); |
|
399 |
|
400 nsRefPtr<IDirect3DSurface9> renderTarget; |
|
401 d3d9Device->GetRenderTarget(0, getter_AddRefs(renderTarget)); |
|
402 mDeviceManager->GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)aRect.width, |
|
403 (unsigned int)aRect.height, |
|
404 (HANDLE)(sourceY->GetD3D9Texture()), |
|
405 (HANDLE)(renderTarget)); |
|
406 } |
|
407 } |
|
408 |
|
409 // Linear scaling is default here, adhering to mFilter is difficult since |
|
410 // presumably even with point filtering we'll still want chroma upsampling |
|
411 // to be linear. In the current approach we can't. |
|
412 device()->SetTexture(Y, sourceY->GetD3D9Texture()); |
|
413 device()->SetTexture(Cb, sourceCb->GetD3D9Texture()); |
|
414 device()->SetTexture(Cr, sourceCr->GetD3D9Texture()); |
|
415 maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER, maskType); |
|
416 } |
|
417 break; |
|
418 case EFFECT_COMPONENT_ALPHA: |
|
419 { |
|
420 MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled()); |
|
421 EffectComponentAlpha* effectComponentAlpha = |
|
422 static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get()); |
|
423 TextureSourceD3D9* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D9(); |
|
424 TextureSourceD3D9* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D9(); |
|
425 |
|
426 Rect textureCoords = effectComponentAlpha->mTextureCoords; |
|
427 d3d9Device->SetVertexShaderConstantF(CBvTextureCoords, |
|
428 ShaderConstantRect( |
|
429 textureCoords.x, |
|
430 textureCoords.y, |
|
431 textureCoords.width, |
|
432 textureCoords.height), |
|
433 1); |
|
434 |
|
435 SetSamplerForFilter(effectComponentAlpha->mFilter); |
|
436 |
|
437 maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1, maskType); |
|
438 SetMask(aEffectChain, maskTexture); |
|
439 d3d9Device->SetTexture(0, sourceOnBlack->GetD3D9Texture()); |
|
440 d3d9Device->SetTexture(1, sourceOnWhite->GetD3D9Texture()); |
|
441 d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); |
|
442 d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR); |
|
443 d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); |
|
444 |
|
445 maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2, maskType); |
|
446 SetMask(aEffectChain, maskTexture); |
|
447 d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); |
|
448 d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); |
|
449 d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); |
|
450 |
|
451 // Restore defaults |
|
452 d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); |
|
453 d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); |
|
454 d3d9Device->SetTexture(1, nullptr); |
|
455 } |
|
456 return; |
|
457 default: |
|
458 NS_WARNING("Unknown shader type"); |
|
459 return; |
|
460 } |
|
461 |
|
462 SetMask(aEffectChain, maskTexture); |
|
463 |
|
464 if (!isPremultiplied) { |
|
465 d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); |
|
466 } |
|
467 |
|
468 HRESULT hr = d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); |
|
469 |
|
470 if (!isPremultiplied) { |
|
471 d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); |
|
472 } |
|
473 } |
|
474 |
|
475 void |
|
476 CompositorD3D9::SetMask(const EffectChain &aEffectChain, uint32_t aMaskTexture) |
|
477 { |
|
478 EffectMask *maskEffect = |
|
479 static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get()); |
|
480 if (!maskEffect) { |
|
481 return; |
|
482 } |
|
483 |
|
484 TextureSourceD3D9 *source = maskEffect->mMaskTexture->AsSourceD3D9(); |
|
485 |
|
486 MOZ_ASSERT(aMaskTexture >= 0); |
|
487 device()->SetTexture(aMaskTexture, source->GetD3D9Texture()); |
|
488 |
|
489 const gfx::Matrix4x4& maskTransform = maskEffect->mMaskTransform; |
|
490 NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!"); |
|
491 Rect bounds = Rect(Point(), Size(maskEffect->mSize)); |
|
492 bounds = maskTransform.As2D().TransformBounds(bounds); |
|
493 |
|
494 device()->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister, |
|
495 ShaderConstantRect(bounds.x, |
|
496 bounds.y, |
|
497 bounds.width, |
|
498 bounds.height), |
|
499 1); |
|
500 } |
|
501 |
|
502 /** |
|
503 * In the next few methods we call |mParent->SendInvalidateAll()| - that has |
|
504 * a few uses - if our device or swap chain is not ready, it causes us to try |
|
505 * to render again, that means we keep trying to get a good device and swap |
|
506 * chain and don't block the main thread (which we would if we kept trying in |
|
507 * a busy loop because this is likely to happen in a sync transaction). |
|
508 * If we had to recreate our device, then we have new textures and we |
|
509 * need to reupload everything (not just what is currently invalid) from the |
|
510 * client side. That means we need to invalidate everything on the client. |
|
511 * If we just reset and didn't need to recreate, then we don't need to reupload |
|
512 * our textures, but we do need to redraw the whole window, which means we still |
|
513 * need to invalidate everything. |
|
514 * Currently we probably do this complete invalidation too much. But it is better |
|
515 * to do that than to miss an invalidation which would result in a black layer |
|
516 * (or multiple layers) until the user moves the mouse. The unnecessary invalidtion |
|
517 * only happens when the device is reset, so that should be pretty rare and when |
|
518 * other things are happening so the user does not expect super performance. |
|
519 */ |
|
520 |
|
521 bool |
|
522 CompositorD3D9::EnsureSwapChain() |
|
523 { |
|
524 MOZ_ASSERT(mDeviceManager, "Don't call EnsureSwapChain without a device manager"); |
|
525 |
|
526 if (!mSwapChain) { |
|
527 mSwapChain = mDeviceManager-> |
|
528 CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW)); |
|
529 // We could not create a swap chain, return false |
|
530 if (!mSwapChain) { |
|
531 // Check the state of the device too |
|
532 DeviceManagerState state = mDeviceManager->VerifyReadyForRendering(); |
|
533 if (state == DeviceMustRecreate) { |
|
534 mDeviceManager = nullptr; |
|
535 } |
|
536 mParent->SendInvalidateAll(); |
|
537 return false; |
|
538 } |
|
539 } |
|
540 |
|
541 // We have a swap chain, lets initialise it |
|
542 DeviceManagerState state = mSwapChain->PrepareForRendering(); |
|
543 if (state == DeviceOK) { |
|
544 return true; |
|
545 } |
|
546 // Swap chain could not be initialised, handle the failure |
|
547 if (state == DeviceMustRecreate) { |
|
548 mDeviceManager = nullptr; |
|
549 mSwapChain = nullptr; |
|
550 } |
|
551 mParent->SendInvalidateAll(); |
|
552 return false; |
|
553 } |
|
554 |
|
555 void |
|
556 CompositorD3D9::CheckResetCount() |
|
557 { |
|
558 if (mDeviceResetCount != mDeviceManager->GetDeviceResetCount()) { |
|
559 mParent->SendInvalidateAll(); |
|
560 } |
|
561 mDeviceResetCount = mDeviceManager->GetDeviceResetCount(); |
|
562 } |
|
563 |
|
564 bool |
|
565 CompositorD3D9::Ready() |
|
566 { |
|
567 if (mDeviceManager) { |
|
568 if (EnsureSwapChain()) { |
|
569 // We don't need to call VerifyReadyForRendering because that is |
|
570 // called by mSwapChain->PrepareForRendering() via EnsureSwapChain(). |
|
571 |
|
572 CheckResetCount(); |
|
573 return true; |
|
574 } |
|
575 return false; |
|
576 } |
|
577 |
|
578 NS_ASSERTION(!mCurrentRT && !mDefaultRT, |
|
579 "Shouldn't have any render targets around, they must be released before our device"); |
|
580 mSwapChain = nullptr; |
|
581 |
|
582 mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); |
|
583 if (!mDeviceManager) { |
|
584 mParent->SendInvalidateAll(); |
|
585 return false; |
|
586 } |
|
587 if (EnsureSwapChain()) { |
|
588 CheckResetCount(); |
|
589 return true; |
|
590 } |
|
591 return false; |
|
592 } |
|
593 |
|
594 static void |
|
595 CancelCompositing(Rect* aRenderBoundsOut) |
|
596 { |
|
597 if (aRenderBoundsOut) { |
|
598 *aRenderBoundsOut = Rect(0, 0, 0, 0); |
|
599 } |
|
600 } |
|
601 |
|
602 void |
|
603 CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion, |
|
604 const Rect *aClipRectIn, |
|
605 const gfx::Matrix& aTransform, |
|
606 const Rect& aRenderBounds, |
|
607 Rect *aClipRectOut, |
|
608 Rect *aRenderBoundsOut) |
|
609 { |
|
610 MOZ_ASSERT(mDeviceManager && mSwapChain); |
|
611 |
|
612 mDeviceManager->SetupRenderState(); |
|
613 |
|
614 EnsureSize(); |
|
615 |
|
616 device()->Clear(0, nullptr, D3DCLEAR_TARGET, 0x00000000, 0, 0); |
|
617 device()->BeginScene(); |
|
618 |
|
619 if (aClipRectOut) { |
|
620 *aClipRectOut = Rect(0, 0, mSize.width, mSize.height); |
|
621 } |
|
622 if (aRenderBoundsOut) { |
|
623 *aRenderBoundsOut = Rect(0, 0, mSize.width, mSize.height); |
|
624 } |
|
625 |
|
626 RECT r; |
|
627 if (aClipRectIn) { |
|
628 r.left = (LONG)aClipRectIn->x; |
|
629 r.top = (LONG)aClipRectIn->y; |
|
630 r.right = (LONG)(aClipRectIn->x + aClipRectIn->width); |
|
631 r.bottom = (LONG)(aClipRectIn->y + aClipRectIn->height); |
|
632 } else { |
|
633 r.left = r.top = 0; |
|
634 r.right = mSize.width; |
|
635 r.bottom = mSize.height; |
|
636 } |
|
637 device()->SetScissorRect(&r); |
|
638 |
|
639 nsRefPtr<IDirect3DSurface9> backBuffer = mSwapChain->GetBackBuffer(); |
|
640 mDefaultRT = new CompositingRenderTargetD3D9(backBuffer, |
|
641 INIT_MODE_CLEAR, |
|
642 IntRect(0, 0, mSize.width, mSize.height)); |
|
643 SetRenderTarget(mDefaultRT); |
|
644 } |
|
645 |
|
646 void |
|
647 CompositorD3D9::EndFrame() |
|
648 { |
|
649 if (mDeviceManager) { |
|
650 device()->EndScene(); |
|
651 |
|
652 nsIntSize oldSize = mSize; |
|
653 EnsureSize(); |
|
654 if (oldSize == mSize) { |
|
655 if (mTarget) { |
|
656 PaintToTarget(); |
|
657 } else { |
|
658 mSwapChain->Present(); |
|
659 } |
|
660 } |
|
661 } |
|
662 |
|
663 mCurrentRT = nullptr; |
|
664 mDefaultRT = nullptr; |
|
665 } |
|
666 |
|
667 void |
|
668 CompositorD3D9::PrepareViewport(const gfx::IntSize& aSize, |
|
669 const Matrix &aWorldTransform) |
|
670 { |
|
671 Matrix4x4 viewMatrix; |
|
672 /* |
|
673 * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, |
|
674 * <1.0, -1.0> bottomright) |
|
675 */ |
|
676 viewMatrix._11 = 2.0f / aSize.width; |
|
677 viewMatrix._22 = -2.0f / aSize.height; |
|
678 viewMatrix._41 = -1.0f; |
|
679 viewMatrix._42 = 1.0f; |
|
680 |
|
681 viewMatrix = Matrix4x4::From2D(aWorldTransform) * viewMatrix; |
|
682 |
|
683 HRESULT hr = device()->SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4); |
|
684 |
|
685 if (FAILED(hr)) { |
|
686 NS_WARNING("Failed to set projection matrix"); |
|
687 } |
|
688 } |
|
689 |
|
690 void |
|
691 CompositorD3D9::EnsureSize() |
|
692 { |
|
693 nsIntRect rect; |
|
694 mWidget->GetClientBounds(rect); |
|
695 |
|
696 mSize = rect.Size(); |
|
697 } |
|
698 |
|
699 void |
|
700 CompositorD3D9::SetSamplerForFilter(Filter aFilter) |
|
701 { |
|
702 switch (aFilter) { |
|
703 case Filter::LINEAR: |
|
704 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); |
|
705 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); |
|
706 return; |
|
707 case Filter::POINT: |
|
708 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); |
|
709 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); |
|
710 return; |
|
711 default: |
|
712 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); |
|
713 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); |
|
714 } |
|
715 } |
|
716 |
|
717 void |
|
718 CompositorD3D9::PaintToTarget() |
|
719 { |
|
720 if (!mDeviceManager) { |
|
721 return; |
|
722 } |
|
723 |
|
724 nsRefPtr<IDirect3DSurface9> backBuff; |
|
725 nsRefPtr<IDirect3DSurface9> destSurf; |
|
726 device()->GetRenderTarget(0, getter_AddRefs(backBuff)); |
|
727 |
|
728 D3DSURFACE_DESC desc; |
|
729 backBuff->GetDesc(&desc); |
|
730 |
|
731 device()->CreateOffscreenPlainSurface(desc.Width, desc.Height, |
|
732 D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, |
|
733 getter_AddRefs(destSurf), nullptr); |
|
734 |
|
735 device()->GetRenderTargetData(backBuff, destSurf); |
|
736 |
|
737 D3DLOCKED_RECT rect; |
|
738 destSurf->LockRect(&rect, nullptr, D3DLOCK_READONLY); |
|
739 RefPtr<DataSourceSurface> sourceSurface = |
|
740 Factory::CreateWrappingDataSourceSurface((uint8_t*)rect.pBits, |
|
741 rect.Pitch, |
|
742 IntSize(desc.Width, desc.Height), |
|
743 SurfaceFormat::B8G8R8A8); |
|
744 mTarget->CopySurface(sourceSurface, |
|
745 IntRect(0, 0, desc.Width, desc.Height), |
|
746 IntPoint()); |
|
747 mTarget->Flush(); |
|
748 destSurf->UnlockRect(); |
|
749 } |
|
750 |
|
751 void |
|
752 CompositorD3D9::ReportFailure(const nsACString &aMsg, HRESULT aCode) |
|
753 { |
|
754 // We could choose to abort here when hr == E_OUTOFMEMORY. |
|
755 nsCString msg; |
|
756 msg.Append(aMsg); |
|
757 msg.AppendLiteral(" Error code: "); |
|
758 msg.AppendInt(uint32_t(aCode)); |
|
759 NS_WARNING(msg.BeginReading()); |
|
760 |
|
761 gfx::LogFailure(msg); |
|
762 } |
|
763 |
|
764 } |
|
765 } |