michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "CompositorD3D9.h" michael@0: #include "LayerManagerD3D9Shaders.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "nsIWidget.h" michael@0: #include "mozilla/layers/ImageHost.h" michael@0: #include "mozilla/layers/ContentHost.h" michael@0: #include "mozilla/layers/Effects.h" michael@0: #include "nsWindowsHelpers.h" michael@0: #include "Nv3DVUtils.h" michael@0: #include "gfxFailure.h" michael@0: #include "mozilla/layers/PCompositorParent.h" michael@0: #include "mozilla/layers/LayerManagerComposite.h" michael@0: #include "gfxPrefs.h" michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: CompositorD3D9::CompositorD3D9(PCompositorParent* aParent, nsIWidget *aWidget) michael@0: : Compositor(aParent) michael@0: , mWidget(aWidget) michael@0: , mDeviceResetCount(0) michael@0: { michael@0: Compositor::SetBackend(LayersBackend::LAYERS_D3D9); michael@0: } michael@0: michael@0: CompositorD3D9::~CompositorD3D9() michael@0: { michael@0: mSwapChain = nullptr; michael@0: mDeviceManager = nullptr; michael@0: } michael@0: michael@0: bool michael@0: CompositorD3D9::Initialize() michael@0: { michael@0: if (!gfxPlatform::CanUseDirect3D9()) { michael@0: NS_WARNING("Direct3D 9-accelerated layers are not supported on this system."); michael@0: return false; michael@0: } michael@0: michael@0: mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); michael@0: if (!mDeviceManager) { michael@0: return false; michael@0: } michael@0: michael@0: mSwapChain = mDeviceManager-> michael@0: CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW)); michael@0: michael@0: if (!mSwapChain) { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: TextureFactoryIdentifier michael@0: CompositorD3D9::GetTextureFactoryIdentifier() michael@0: { michael@0: TextureFactoryIdentifier ident; michael@0: ident.mMaxTextureSize = GetMaxTextureSize(); michael@0: ident.mParentBackend = LayersBackend::LAYERS_D3D9; michael@0: ident.mParentProcessId = XRE_GetProcessType(); michael@0: return ident; michael@0: } michael@0: michael@0: bool michael@0: CompositorD3D9::CanUseCanvasLayerForSize(const IntSize &aSize) michael@0: { michael@0: int32_t maxTextureSize = GetMaxTextureSize(); michael@0: michael@0: if (aSize.width > maxTextureSize || aSize.height > maxTextureSize) { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: int32_t michael@0: CompositorD3D9::GetMaxTextureSize() const michael@0: { michael@0: return mDeviceManager ? mDeviceManager->GetMaxTextureSize() : INT32_MAX; michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorD3D9::CreateDataTextureSource(TextureFlags aFlags) michael@0: { michael@0: return new DataTextureSourceD3D9(SurfaceFormat::UNKNOWN, this, aFlags); michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorD3D9::CreateRenderTarget(const gfx::IntRect &aRect, michael@0: SurfaceInitMode aInit) michael@0: { michael@0: if (!mDeviceManager) { michael@0: return nullptr; michael@0: } michael@0: michael@0: RefPtr texture; michael@0: HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1, michael@0: D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, michael@0: D3DPOOL_DEFAULT, byRef(texture), michael@0: nullptr); michael@0: if (FAILED(hr)) { michael@0: ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTarget: Failed to create texture"), michael@0: hr); michael@0: return nullptr; michael@0: } michael@0: michael@0: RefPtr rt = michael@0: new CompositingRenderTargetD3D9(texture, aInit, aRect); michael@0: michael@0: return rt; michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorD3D9::CreateRenderTargetFromSource(const gfx::IntRect &aRect, michael@0: const CompositingRenderTarget *aSource, michael@0: const gfx::IntPoint &aSourcePoint) michael@0: { michael@0: if (!mDeviceManager) { michael@0: return nullptr; michael@0: } michael@0: michael@0: RefPtr texture; michael@0: HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1, michael@0: D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, michael@0: D3DPOOL_DEFAULT, byRef(texture), michael@0: nullptr); michael@0: if (FAILED(hr)) { michael@0: ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to create texture"), michael@0: hr); michael@0: return nullptr; michael@0: } michael@0: michael@0: if (aSource) { michael@0: nsRefPtr sourceSurface = michael@0: static_cast(aSource)->GetD3D9Surface(); michael@0: michael@0: nsRefPtr destSurface; michael@0: hr = texture->GetSurfaceLevel(0, getter_AddRefs(destSurface)); michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to get texture surface level for dest."); michael@0: } michael@0: michael@0: if (sourceSurface && destSurface) { michael@0: RECT sourceRect; michael@0: sourceRect.left = aSourcePoint.x; michael@0: sourceRect.right = aSourcePoint.x + aRect.width; michael@0: sourceRect.top = aSourcePoint.y; michael@0: sourceRect.bottom = aSourcePoint.y + aRect.height; michael@0: RECT destRect; michael@0: destRect.left = 0; michael@0: destRect.right = aRect.width; michael@0: destRect.top = 0; michael@0: destRect.bottom = aRect.height; michael@0: michael@0: // copy the source to the dest michael@0: hr = device()->StretchRect(sourceSurface, michael@0: &sourceRect, michael@0: destSurface, michael@0: &destRect, michael@0: D3DTEXF_NONE); michael@0: if (FAILED(hr)) { michael@0: ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to update texture"), michael@0: hr); michael@0: } michael@0: } michael@0: } michael@0: michael@0: RefPtr rt = michael@0: new CompositingRenderTargetD3D9(texture, michael@0: INIT_MODE_NONE, michael@0: aRect); michael@0: michael@0: return rt; michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::SetRenderTarget(CompositingRenderTarget *aRenderTarget) michael@0: { michael@0: MOZ_ASSERT(aRenderTarget && mDeviceManager); michael@0: RefPtr oldRT = mCurrentRT; michael@0: mCurrentRT = static_cast(aRenderTarget); michael@0: mCurrentRT->BindRenderTarget(device()); michael@0: PrepareViewport(mCurrentRT->GetSize(), Matrix()); michael@0: } michael@0: michael@0: static DeviceManagerD3D9::ShaderMode michael@0: ShaderModeForEffectType(EffectTypes aEffectType, gfx::SurfaceFormat aFormat) michael@0: { michael@0: switch (aEffectType) { michael@0: case EFFECT_SOLID_COLOR: michael@0: return DeviceManagerD3D9::SOLIDCOLORLAYER; michael@0: case EFFECT_RENDER_TARGET: michael@0: return DeviceManagerD3D9::RGBALAYER; michael@0: case EFFECT_RGB: michael@0: if (aFormat == SurfaceFormat::B8G8R8A8 || aFormat == SurfaceFormat::R8G8B8A8) michael@0: return DeviceManagerD3D9::RGBALAYER; michael@0: return DeviceManagerD3D9::RGBLAYER; michael@0: case EFFECT_YCBCR: michael@0: return DeviceManagerD3D9::YCBCRLAYER; michael@0: } michael@0: michael@0: MOZ_CRASH("Bad effect type"); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::ClearRect(const gfx::Rect& aRect) michael@0: { michael@0: D3DRECT rect; michael@0: rect.x1 = aRect.X(); michael@0: rect.y1 = aRect.Y(); michael@0: rect.x2 = aRect.XMost(); michael@0: rect.y2 = aRect.YMost(); michael@0: michael@0: device()->Clear(1, &rect, D3DCLEAR_TARGET, michael@0: 0x00000000, 0, 0); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::DrawQuad(const gfx::Rect &aRect, michael@0: const gfx::Rect &aClipRect, michael@0: const EffectChain &aEffectChain, michael@0: gfx::Float aOpacity, michael@0: const gfx::Matrix4x4 &aTransform) michael@0: { michael@0: if (!mDeviceManager) { michael@0: return; michael@0: } michael@0: michael@0: IDirect3DDevice9* d3d9Device = device(); michael@0: MOZ_ASSERT(d3d9Device, "We should be able to get a device now"); michael@0: michael@0: MOZ_ASSERT(mCurrentRT, "No render target"); michael@0: d3d9Device->SetVertexShaderConstantF(CBmLayerTransform, &aTransform._11, 4); michael@0: michael@0: IntPoint origin = mCurrentRT->GetOrigin(); michael@0: float renderTargetOffset[] = { origin.x, origin.y, 0, 0 }; michael@0: d3d9Device->SetVertexShaderConstantF(CBvRenderTargetOffset, michael@0: renderTargetOffset, michael@0: 1); michael@0: d3d9Device->SetVertexShaderConstantF(CBvLayerQuad, michael@0: ShaderConstantRect(aRect.x, michael@0: aRect.y, michael@0: aRect.width, michael@0: aRect.height), michael@0: 1); michael@0: bool target = false; michael@0: michael@0: if (aEffectChain.mPrimaryEffect->mType != EFFECT_SOLID_COLOR) { michael@0: float opacity[4]; michael@0: /* michael@0: * We always upload a 4 component float, but the shader will use only the michael@0: * first component since it's declared as a 'float'. michael@0: */ michael@0: opacity[0] = aOpacity; michael@0: d3d9Device->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1); michael@0: } michael@0: michael@0: bool isPremultiplied = true; michael@0: michael@0: MaskType maskType = MaskNone; michael@0: michael@0: if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) { michael@0: if (aTransform.Is2D()) { michael@0: maskType = Mask2d; michael@0: } else { michael@0: maskType = Mask3d; michael@0: } michael@0: } michael@0: michael@0: RECT scissor; michael@0: scissor.left = aClipRect.x; michael@0: scissor.right = aClipRect.XMost(); michael@0: scissor.top = aClipRect.y; michael@0: scissor.bottom = aClipRect.YMost(); michael@0: d3d9Device->SetScissorRect(&scissor); michael@0: michael@0: uint32_t maskTexture = 0; michael@0: switch (aEffectChain.mPrimaryEffect->mType) { michael@0: case EFFECT_SOLID_COLOR: michael@0: { michael@0: // output color is premultiplied, so we need to adjust all channels. michael@0: Color layerColor = michael@0: static_cast(aEffectChain.mPrimaryEffect.get())->mColor; michael@0: float color[4]; michael@0: color[0] = layerColor.r * layerColor.a * aOpacity; michael@0: color[1] = layerColor.g * layerColor.a * aOpacity; michael@0: color[2] = layerColor.b * layerColor.a * aOpacity; michael@0: color[3] = layerColor.a * aOpacity; michael@0: michael@0: d3d9Device->SetPixelShaderConstantF(CBvColor, color, 1); michael@0: michael@0: maskTexture = mDeviceManager michael@0: ->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER, maskType); michael@0: } michael@0: break; michael@0: case EFFECT_RENDER_TARGET: michael@0: case EFFECT_RGB: michael@0: { michael@0: TexturedEffect* texturedEffect = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: michael@0: Rect textureCoords = texturedEffect->mTextureCoords; michael@0: d3d9Device->SetVertexShaderConstantF(CBvTextureCoords, michael@0: ShaderConstantRect( michael@0: textureCoords.x, michael@0: textureCoords.y, michael@0: textureCoords.width, michael@0: textureCoords.height), michael@0: 1); michael@0: michael@0: SetSamplerForFilter(texturedEffect->mFilter); michael@0: michael@0: TextureSourceD3D9* source = texturedEffect->mTexture->AsSourceD3D9(); michael@0: d3d9Device->SetTexture(0, source->GetD3D9Texture()); michael@0: michael@0: maskTexture = mDeviceManager michael@0: ->SetShaderMode(ShaderModeForEffectType(aEffectChain.mPrimaryEffect->mType, michael@0: texturedEffect->mTexture->GetFormat()), michael@0: maskType); michael@0: michael@0: isPremultiplied = texturedEffect->mPremultiplied; michael@0: } michael@0: break; michael@0: case EFFECT_YCBCR: michael@0: { michael@0: EffectYCbCr* ycbcrEffect = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: michael@0: SetSamplerForFilter(Filter::LINEAR); michael@0: michael@0: Rect textureCoords = ycbcrEffect->mTextureCoords; michael@0: d3d9Device->SetVertexShaderConstantF(CBvTextureCoords, michael@0: ShaderConstantRect( michael@0: textureCoords.x, michael@0: textureCoords.y, michael@0: textureCoords.width, michael@0: textureCoords.height), michael@0: 1); michael@0: michael@0: const int Y = 0, Cb = 1, Cr = 2; michael@0: TextureSource* source = ycbcrEffect->mTexture; michael@0: michael@0: if (!source) { michael@0: NS_WARNING("No texture to composite"); michael@0: return; michael@0: } michael@0: michael@0: if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) || !source->GetSubSource(Cr)) { michael@0: // This can happen if we failed to upload the textures, most likely michael@0: // because of unsupported dimensions (we don't tile YCbCr textures). michael@0: return; michael@0: } michael@0: michael@0: TextureSourceD3D9* sourceY = source->GetSubSource(Y)->AsSourceD3D9(); michael@0: TextureSourceD3D9* sourceCb = source->GetSubSource(Cb)->AsSourceD3D9(); michael@0: TextureSourceD3D9* sourceCr = source->GetSubSource(Cr)->AsSourceD3D9(); michael@0: michael@0: michael@0: MOZ_ASSERT(sourceY->GetD3D9Texture()); michael@0: MOZ_ASSERT(sourceCb->GetD3D9Texture()); michael@0: MOZ_ASSERT(sourceCr->GetD3D9Texture()); michael@0: michael@0: /* michael@0: * Send 3d control data and metadata michael@0: */ michael@0: if (mDeviceManager->GetNv3DVUtils()) { michael@0: Nv_Stereo_Mode mode; michael@0: switch (source->AsSourceD3D9()->GetStereoMode()) { michael@0: case StereoMode::LEFT_RIGHT: michael@0: mode = NV_STEREO_MODE_LEFT_RIGHT; michael@0: break; michael@0: case StereoMode::RIGHT_LEFT: michael@0: mode = NV_STEREO_MODE_RIGHT_LEFT; michael@0: break; michael@0: case StereoMode::BOTTOM_TOP: michael@0: mode = NV_STEREO_MODE_BOTTOM_TOP; michael@0: break; michael@0: case StereoMode::TOP_BOTTOM: michael@0: mode = NV_STEREO_MODE_TOP_BOTTOM; michael@0: break; michael@0: case StereoMode::MONO: michael@0: mode = NV_STEREO_MODE_MONO; michael@0: break; michael@0: } michael@0: michael@0: // Send control data even in mono case so driver knows to leave stereo mode. michael@0: mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE); michael@0: michael@0: if (source->AsSourceD3D9()->GetStereoMode() != StereoMode::MONO) { michael@0: mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE); michael@0: michael@0: nsRefPtr renderTarget; michael@0: d3d9Device->GetRenderTarget(0, getter_AddRefs(renderTarget)); michael@0: mDeviceManager->GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)aRect.width, michael@0: (unsigned int)aRect.height, michael@0: (HANDLE)(sourceY->GetD3D9Texture()), michael@0: (HANDLE)(renderTarget)); michael@0: } michael@0: } michael@0: michael@0: // Linear scaling is default here, adhering to mFilter is difficult since michael@0: // presumably even with point filtering we'll still want chroma upsampling michael@0: // to be linear. In the current approach we can't. michael@0: device()->SetTexture(Y, sourceY->GetD3D9Texture()); michael@0: device()->SetTexture(Cb, sourceCb->GetD3D9Texture()); michael@0: device()->SetTexture(Cr, sourceCr->GetD3D9Texture()); michael@0: maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER, maskType); michael@0: } michael@0: break; michael@0: case EFFECT_COMPONENT_ALPHA: michael@0: { michael@0: MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled()); michael@0: EffectComponentAlpha* effectComponentAlpha = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: TextureSourceD3D9* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D9(); michael@0: TextureSourceD3D9* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D9(); michael@0: michael@0: Rect textureCoords = effectComponentAlpha->mTextureCoords; michael@0: d3d9Device->SetVertexShaderConstantF(CBvTextureCoords, michael@0: ShaderConstantRect( michael@0: textureCoords.x, michael@0: textureCoords.y, michael@0: textureCoords.width, michael@0: textureCoords.height), michael@0: 1); michael@0: michael@0: SetSamplerForFilter(effectComponentAlpha->mFilter); michael@0: michael@0: maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1, maskType); michael@0: SetMask(aEffectChain, maskTexture); michael@0: d3d9Device->SetTexture(0, sourceOnBlack->GetD3D9Texture()); michael@0: d3d9Device->SetTexture(1, sourceOnWhite->GetD3D9Texture()); michael@0: d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); michael@0: d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR); michael@0: d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); michael@0: michael@0: maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2, maskType); michael@0: SetMask(aEffectChain, maskTexture); michael@0: d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); michael@0: d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); michael@0: d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); michael@0: michael@0: // Restore defaults michael@0: d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); michael@0: d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); michael@0: d3d9Device->SetTexture(1, nullptr); michael@0: } michael@0: return; michael@0: default: michael@0: NS_WARNING("Unknown shader type"); michael@0: return; michael@0: } michael@0: michael@0: SetMask(aEffectChain, maskTexture); michael@0: michael@0: if (!isPremultiplied) { michael@0: d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); michael@0: } michael@0: michael@0: HRESULT hr = d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); michael@0: michael@0: if (!isPremultiplied) { michael@0: d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::SetMask(const EffectChain &aEffectChain, uint32_t aMaskTexture) michael@0: { michael@0: EffectMask *maskEffect = michael@0: static_cast(aEffectChain.mSecondaryEffects[EFFECT_MASK].get()); michael@0: if (!maskEffect) { michael@0: return; michael@0: } michael@0: michael@0: TextureSourceD3D9 *source = maskEffect->mMaskTexture->AsSourceD3D9(); michael@0: michael@0: MOZ_ASSERT(aMaskTexture >= 0); michael@0: device()->SetTexture(aMaskTexture, source->GetD3D9Texture()); michael@0: michael@0: const gfx::Matrix4x4& maskTransform = maskEffect->mMaskTransform; michael@0: NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!"); michael@0: Rect bounds = Rect(Point(), Size(maskEffect->mSize)); michael@0: bounds = maskTransform.As2D().TransformBounds(bounds); michael@0: michael@0: device()->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister, michael@0: ShaderConstantRect(bounds.x, michael@0: bounds.y, michael@0: bounds.width, michael@0: bounds.height), michael@0: 1); michael@0: } michael@0: michael@0: /** michael@0: * In the next few methods we call |mParent->SendInvalidateAll()| - that has michael@0: * a few uses - if our device or swap chain is not ready, it causes us to try michael@0: * to render again, that means we keep trying to get a good device and swap michael@0: * chain and don't block the main thread (which we would if we kept trying in michael@0: * a busy loop because this is likely to happen in a sync transaction). michael@0: * If we had to recreate our device, then we have new textures and we michael@0: * need to reupload everything (not just what is currently invalid) from the michael@0: * client side. That means we need to invalidate everything on the client. michael@0: * If we just reset and didn't need to recreate, then we don't need to reupload michael@0: * our textures, but we do need to redraw the whole window, which means we still michael@0: * need to invalidate everything. michael@0: * Currently we probably do this complete invalidation too much. But it is better michael@0: * to do that than to miss an invalidation which would result in a black layer michael@0: * (or multiple layers) until the user moves the mouse. The unnecessary invalidtion michael@0: * only happens when the device is reset, so that should be pretty rare and when michael@0: * other things are happening so the user does not expect super performance. michael@0: */ michael@0: michael@0: bool michael@0: CompositorD3D9::EnsureSwapChain() michael@0: { michael@0: MOZ_ASSERT(mDeviceManager, "Don't call EnsureSwapChain without a device manager"); michael@0: michael@0: if (!mSwapChain) { michael@0: mSwapChain = mDeviceManager-> michael@0: CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW)); michael@0: // We could not create a swap chain, return false michael@0: if (!mSwapChain) { michael@0: // Check the state of the device too michael@0: DeviceManagerState state = mDeviceManager->VerifyReadyForRendering(); michael@0: if (state == DeviceMustRecreate) { michael@0: mDeviceManager = nullptr; michael@0: } michael@0: mParent->SendInvalidateAll(); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // We have a swap chain, lets initialise it michael@0: DeviceManagerState state = mSwapChain->PrepareForRendering(); michael@0: if (state == DeviceOK) { michael@0: return true; michael@0: } michael@0: // Swap chain could not be initialised, handle the failure michael@0: if (state == DeviceMustRecreate) { michael@0: mDeviceManager = nullptr; michael@0: mSwapChain = nullptr; michael@0: } michael@0: mParent->SendInvalidateAll(); michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::CheckResetCount() michael@0: { michael@0: if (mDeviceResetCount != mDeviceManager->GetDeviceResetCount()) { michael@0: mParent->SendInvalidateAll(); michael@0: } michael@0: mDeviceResetCount = mDeviceManager->GetDeviceResetCount(); michael@0: } michael@0: michael@0: bool michael@0: CompositorD3D9::Ready() michael@0: { michael@0: if (mDeviceManager) { michael@0: if (EnsureSwapChain()) { michael@0: // We don't need to call VerifyReadyForRendering because that is michael@0: // called by mSwapChain->PrepareForRendering() via EnsureSwapChain(). michael@0: michael@0: CheckResetCount(); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: NS_ASSERTION(!mCurrentRT && !mDefaultRT, michael@0: "Shouldn't have any render targets around, they must be released before our device"); michael@0: mSwapChain = nullptr; michael@0: michael@0: mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); michael@0: if (!mDeviceManager) { michael@0: mParent->SendInvalidateAll(); michael@0: return false; michael@0: } michael@0: if (EnsureSwapChain()) { michael@0: CheckResetCount(); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: static void michael@0: CancelCompositing(Rect* aRenderBoundsOut) michael@0: { michael@0: if (aRenderBoundsOut) { michael@0: *aRenderBoundsOut = Rect(0, 0, 0, 0); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion, michael@0: const Rect *aClipRectIn, michael@0: const gfx::Matrix& aTransform, michael@0: const Rect& aRenderBounds, michael@0: Rect *aClipRectOut, michael@0: Rect *aRenderBoundsOut) michael@0: { michael@0: MOZ_ASSERT(mDeviceManager && mSwapChain); michael@0: michael@0: mDeviceManager->SetupRenderState(); michael@0: michael@0: EnsureSize(); michael@0: michael@0: device()->Clear(0, nullptr, D3DCLEAR_TARGET, 0x00000000, 0, 0); michael@0: device()->BeginScene(); michael@0: michael@0: if (aClipRectOut) { michael@0: *aClipRectOut = Rect(0, 0, mSize.width, mSize.height); michael@0: } michael@0: if (aRenderBoundsOut) { michael@0: *aRenderBoundsOut = Rect(0, 0, mSize.width, mSize.height); michael@0: } michael@0: michael@0: RECT r; michael@0: if (aClipRectIn) { michael@0: r.left = (LONG)aClipRectIn->x; michael@0: r.top = (LONG)aClipRectIn->y; michael@0: r.right = (LONG)(aClipRectIn->x + aClipRectIn->width); michael@0: r.bottom = (LONG)(aClipRectIn->y + aClipRectIn->height); michael@0: } else { michael@0: r.left = r.top = 0; michael@0: r.right = mSize.width; michael@0: r.bottom = mSize.height; michael@0: } michael@0: device()->SetScissorRect(&r); michael@0: michael@0: nsRefPtr backBuffer = mSwapChain->GetBackBuffer(); michael@0: mDefaultRT = new CompositingRenderTargetD3D9(backBuffer, michael@0: INIT_MODE_CLEAR, michael@0: IntRect(0, 0, mSize.width, mSize.height)); michael@0: SetRenderTarget(mDefaultRT); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::EndFrame() michael@0: { michael@0: if (mDeviceManager) { michael@0: device()->EndScene(); michael@0: michael@0: nsIntSize oldSize = mSize; michael@0: EnsureSize(); michael@0: if (oldSize == mSize) { michael@0: if (mTarget) { michael@0: PaintToTarget(); michael@0: } else { michael@0: mSwapChain->Present(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: mCurrentRT = nullptr; michael@0: mDefaultRT = nullptr; michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::PrepareViewport(const gfx::IntSize& aSize, michael@0: const Matrix &aWorldTransform) michael@0: { michael@0: Matrix4x4 viewMatrix; michael@0: /* michael@0: * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, michael@0: * <1.0, -1.0> bottomright) michael@0: */ michael@0: viewMatrix._11 = 2.0f / aSize.width; michael@0: viewMatrix._22 = -2.0f / aSize.height; michael@0: viewMatrix._41 = -1.0f; michael@0: viewMatrix._42 = 1.0f; michael@0: michael@0: viewMatrix = Matrix4x4::From2D(aWorldTransform) * viewMatrix; michael@0: michael@0: HRESULT hr = device()->SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4); michael@0: michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to set projection matrix"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::EnsureSize() michael@0: { michael@0: nsIntRect rect; michael@0: mWidget->GetClientBounds(rect); michael@0: michael@0: mSize = rect.Size(); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::SetSamplerForFilter(Filter aFilter) michael@0: { michael@0: switch (aFilter) { michael@0: case Filter::LINEAR: michael@0: device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); michael@0: device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); michael@0: return; michael@0: case Filter::POINT: michael@0: device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); michael@0: device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); michael@0: return; michael@0: default: michael@0: device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); michael@0: device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::PaintToTarget() michael@0: { michael@0: if (!mDeviceManager) { michael@0: return; michael@0: } michael@0: michael@0: nsRefPtr backBuff; michael@0: nsRefPtr destSurf; michael@0: device()->GetRenderTarget(0, getter_AddRefs(backBuff)); michael@0: michael@0: D3DSURFACE_DESC desc; michael@0: backBuff->GetDesc(&desc); michael@0: michael@0: device()->CreateOffscreenPlainSurface(desc.Width, desc.Height, michael@0: D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, michael@0: getter_AddRefs(destSurf), nullptr); michael@0: michael@0: device()->GetRenderTargetData(backBuff, destSurf); michael@0: michael@0: D3DLOCKED_RECT rect; michael@0: destSurf->LockRect(&rect, nullptr, D3DLOCK_READONLY); michael@0: RefPtr sourceSurface = michael@0: Factory::CreateWrappingDataSourceSurface((uint8_t*)rect.pBits, michael@0: rect.Pitch, michael@0: IntSize(desc.Width, desc.Height), michael@0: SurfaceFormat::B8G8R8A8); michael@0: mTarget->CopySurface(sourceSurface, michael@0: IntRect(0, 0, desc.Width, desc.Height), michael@0: IntPoint()); michael@0: mTarget->Flush(); michael@0: destSurf->UnlockRect(); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D9::ReportFailure(const nsACString &aMsg, HRESULT aCode) michael@0: { michael@0: // We could choose to abort here when hr == E_OUTOFMEMORY. michael@0: nsCString msg; michael@0: msg.Append(aMsg); michael@0: msg.AppendLiteral(" Error code: "); michael@0: msg.AppendInt(uint32_t(aCode)); michael@0: NS_WARNING(msg.BeginReading()); michael@0: michael@0: gfx::LogFailure(msg); michael@0: } michael@0: michael@0: } michael@0: }