gfx/layers/d3d9/CompositorD3D9.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial