Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
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"
20 using namespace mozilla::gfx;
22 namespace mozilla {
23 namespace layers {
25 CompositorD3D9::CompositorD3D9(PCompositorParent* aParent, nsIWidget *aWidget)
26 : Compositor(aParent)
27 , mWidget(aWidget)
28 , mDeviceResetCount(0)
29 {
30 Compositor::SetBackend(LayersBackend::LAYERS_D3D9);
31 }
33 CompositorD3D9::~CompositorD3D9()
34 {
35 mSwapChain = nullptr;
36 mDeviceManager = nullptr;
37 }
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 }
47 mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
48 if (!mDeviceManager) {
49 return false;
50 }
52 mSwapChain = mDeviceManager->
53 CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW));
55 if (!mSwapChain) {
56 return false;
57 }
59 return true;
60 }
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 }
72 bool
73 CompositorD3D9::CanUseCanvasLayerForSize(const IntSize &aSize)
74 {
75 int32_t maxTextureSize = GetMaxTextureSize();
77 if (aSize.width > maxTextureSize || aSize.height > maxTextureSize) {
78 return false;
79 }
81 return true;
82 }
84 int32_t
85 CompositorD3D9::GetMaxTextureSize() const
86 {
87 return mDeviceManager ? mDeviceManager->GetMaxTextureSize() : INT32_MAX;
88 }
90 TemporaryRef<DataTextureSource>
91 CompositorD3D9::CreateDataTextureSource(TextureFlags aFlags)
92 {
93 return new DataTextureSourceD3D9(SurfaceFormat::UNKNOWN, this, aFlags);
94 }
96 TemporaryRef<CompositingRenderTarget>
97 CompositorD3D9::CreateRenderTarget(const gfx::IntRect &aRect,
98 SurfaceInitMode aInit)
99 {
100 if (!mDeviceManager) {
101 return nullptr;
102 }
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 }
115 RefPtr<CompositingRenderTargetD3D9> rt =
116 new CompositingRenderTargetD3D9(texture, aInit, aRect);
118 return rt;
119 }
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 }
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 }
141 if (aSource) {
142 nsRefPtr<IDirect3DSurface9> sourceSurface =
143 static_cast<const CompositingRenderTargetD3D9*>(aSource)->GetD3D9Surface();
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 }
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;
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 }
176 RefPtr<CompositingRenderTargetD3D9> rt =
177 new CompositingRenderTargetD3D9(texture,
178 INIT_MODE_NONE,
179 aRect);
181 return rt;
182 }
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 }
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 }
210 MOZ_CRASH("Bad effect type");
211 }
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();
222 device()->Clear(1, &rect, D3DCLEAR_TARGET,
223 0x00000000, 0, 0);
224 }
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 }
237 IDirect3DDevice9* d3d9Device = device();
238 MOZ_ASSERT(d3d9Device, "We should be able to get a device now");
240 MOZ_ASSERT(mCurrentRT, "No render target");
241 d3d9Device->SetVertexShaderConstantF(CBmLayerTransform, &aTransform._11, 4);
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;
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 }
266 bool isPremultiplied = true;
268 MaskType maskType = MaskNone;
270 if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
271 if (aTransform.Is2D()) {
272 maskType = Mask2d;
273 } else {
274 maskType = Mask3d;
275 }
276 }
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);
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;
298 d3d9Device->SetPixelShaderConstantF(CBvColor, color, 1);
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());
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);
319 SetSamplerForFilter(texturedEffect->mFilter);
321 TextureSourceD3D9* source = texturedEffect->mTexture->AsSourceD3D9();
322 d3d9Device->SetTexture(0, source->GetD3D9Texture());
324 maskTexture = mDeviceManager
325 ->SetShaderMode(ShaderModeForEffectType(aEffectChain.mPrimaryEffect->mType,
326 texturedEffect->mTexture->GetFormat()),
327 maskType);
329 isPremultiplied = texturedEffect->mPremultiplied;
330 }
331 break;
332 case EFFECT_YCBCR:
333 {
334 EffectYCbCr* ycbcrEffect =
335 static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
337 SetSamplerForFilter(Filter::LINEAR);
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);
348 const int Y = 0, Cb = 1, Cr = 2;
349 TextureSource* source = ycbcrEffect->mTexture;
351 if (!source) {
352 NS_WARNING("No texture to composite");
353 return;
354 }
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 }
362 TextureSourceD3D9* sourceY = source->GetSubSource(Y)->AsSourceD3D9();
363 TextureSourceD3D9* sourceCb = source->GetSubSource(Cb)->AsSourceD3D9();
364 TextureSourceD3D9* sourceCr = source->GetSubSource(Cr)->AsSourceD3D9();
367 MOZ_ASSERT(sourceY->GetD3D9Texture());
368 MOZ_ASSERT(sourceCb->GetD3D9Texture());
369 MOZ_ASSERT(sourceCr->GetD3D9Texture());
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 }
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);
397 if (source->AsSourceD3D9()->GetStereoMode() != StereoMode::MONO) {
398 mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE);
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 }
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();
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);
435 SetSamplerForFilter(effectComponentAlpha->mFilter);
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);
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);
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 }
462 SetMask(aEffectChain, maskTexture);
464 if (!isPremultiplied) {
465 d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
466 }
468 HRESULT hr = d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
470 if (!isPremultiplied) {
471 d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
472 }
473 }
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 }
484 TextureSourceD3D9 *source = maskEffect->mMaskTexture->AsSourceD3D9();
486 MOZ_ASSERT(aMaskTexture >= 0);
487 device()->SetTexture(aMaskTexture, source->GetD3D9Texture());
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);
494 device()->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister,
495 ShaderConstantRect(bounds.x,
496 bounds.y,
497 bounds.width,
498 bounds.height),
499 1);
500 }
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 */
521 bool
522 CompositorD3D9::EnsureSwapChain()
523 {
524 MOZ_ASSERT(mDeviceManager, "Don't call EnsureSwapChain without a device manager");
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 }
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 }
555 void
556 CompositorD3D9::CheckResetCount()
557 {
558 if (mDeviceResetCount != mDeviceManager->GetDeviceResetCount()) {
559 mParent->SendInvalidateAll();
560 }
561 mDeviceResetCount = mDeviceManager->GetDeviceResetCount();
562 }
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().
572 CheckResetCount();
573 return true;
574 }
575 return false;
576 }
578 NS_ASSERTION(!mCurrentRT && !mDefaultRT,
579 "Shouldn't have any render targets around, they must be released before our device");
580 mSwapChain = nullptr;
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 }
594 static void
595 CancelCompositing(Rect* aRenderBoundsOut)
596 {
597 if (aRenderBoundsOut) {
598 *aRenderBoundsOut = Rect(0, 0, 0, 0);
599 }
600 }
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);
612 mDeviceManager->SetupRenderState();
614 EnsureSize();
616 device()->Clear(0, nullptr, D3DCLEAR_TARGET, 0x00000000, 0, 0);
617 device()->BeginScene();
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 }
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);
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 }
646 void
647 CompositorD3D9::EndFrame()
648 {
649 if (mDeviceManager) {
650 device()->EndScene();
652 nsIntSize oldSize = mSize;
653 EnsureSize();
654 if (oldSize == mSize) {
655 if (mTarget) {
656 PaintToTarget();
657 } else {
658 mSwapChain->Present();
659 }
660 }
661 }
663 mCurrentRT = nullptr;
664 mDefaultRT = nullptr;
665 }
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;
681 viewMatrix = Matrix4x4::From2D(aWorldTransform) * viewMatrix;
683 HRESULT hr = device()->SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4);
685 if (FAILED(hr)) {
686 NS_WARNING("Failed to set projection matrix");
687 }
688 }
690 void
691 CompositorD3D9::EnsureSize()
692 {
693 nsIntRect rect;
694 mWidget->GetClientBounds(rect);
696 mSize = rect.Size();
697 }
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 }
717 void
718 CompositorD3D9::PaintToTarget()
719 {
720 if (!mDeviceManager) {
721 return;
722 }
724 nsRefPtr<IDirect3DSurface9> backBuff;
725 nsRefPtr<IDirect3DSurface9> destSurf;
726 device()->GetRenderTarget(0, getter_AddRefs(backBuff));
728 D3DSURFACE_DESC desc;
729 backBuff->GetDesc(&desc);
731 device()->CreateOffscreenPlainSurface(desc.Width, desc.Height,
732 D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM,
733 getter_AddRefs(destSurf), nullptr);
735 device()->GetRenderTargetData(backBuff, destSurf);
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 }
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());
761 gfx::LogFailure(msg);
762 }
764 }
765 }