michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 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 "CompositorD3D11.h" michael@0: michael@0: #include "TextureD3D11.h" michael@0: #include "CompositorD3D11Shaders.h" michael@0: 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 "gfxPrefs.h" michael@0: michael@0: #ifdef MOZ_METRO michael@0: #include michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: michael@0: using namespace gfx; michael@0: michael@0: namespace layers { michael@0: michael@0: struct Vertex michael@0: { michael@0: float position[2]; michael@0: }; michael@0: michael@0: // {1E4D7BEB-D8EC-4A0B-BF0A-63E6DE129425} michael@0: static const GUID sDeviceAttachmentsD3D11 = michael@0: { 0x1e4d7beb, 0xd8ec, 0x4a0b, { 0xbf, 0xa, 0x63, 0xe6, 0xde, 0x12, 0x94, 0x25 } }; michael@0: // {88041664-C835-4AA8-ACB8-7EC832357ED8} michael@0: static const GUID sLayerManagerCount = michael@0: { 0x88041664, 0xc835, 0x4aa8, { 0xac, 0xb8, 0x7e, 0xc8, 0x32, 0x35, 0x7e, 0xd8 } }; michael@0: michael@0: const FLOAT sBlendFactor[] = { 0, 0, 0, 0 }; michael@0: michael@0: struct DeviceAttachmentsD3D11 michael@0: { michael@0: RefPtr mInputLayout; michael@0: RefPtr mVertexBuffer; michael@0: RefPtr mVSQuadShader[3]; michael@0: RefPtr mSolidColorShader[2]; michael@0: RefPtr mRGBAShader[3]; michael@0: RefPtr mRGBShader[2]; michael@0: RefPtr mYCbCrShader[2]; michael@0: RefPtr mComponentAlphaShader[2]; michael@0: RefPtr mPSConstantBuffer; michael@0: RefPtr mVSConstantBuffer; michael@0: RefPtr mRasterizerState; michael@0: RefPtr mLinearSamplerState; michael@0: RefPtr mPointSamplerState; michael@0: RefPtr mPremulBlendState; michael@0: RefPtr mNonPremulBlendState; michael@0: RefPtr mComponentBlendState; michael@0: RefPtr mDisabledBlendState; michael@0: }; michael@0: michael@0: CompositorD3D11::CompositorD3D11(nsIWidget* aWidget) michael@0: : mAttachments(nullptr) michael@0: , mWidget(aWidget) michael@0: , mHwnd(nullptr) michael@0: , mDisableSequenceForNextFrame(false) michael@0: { michael@0: SetBackend(LayersBackend::LAYERS_D3D11); michael@0: } michael@0: michael@0: CompositorD3D11::~CompositorD3D11() michael@0: { michael@0: if (mDevice) { michael@0: int referenceCount = 0; michael@0: UINT size = sizeof(referenceCount); michael@0: HRESULT hr = mDevice->GetPrivateData(sLayerManagerCount, &size, &referenceCount); michael@0: NS_ASSERTION(SUCCEEDED(hr), "Reference count not found on device."); michael@0: referenceCount--; michael@0: mDevice->SetPrivateData(sLayerManagerCount, michael@0: sizeof(referenceCount), michael@0: &referenceCount); michael@0: michael@0: if (!referenceCount) { michael@0: DeviceAttachmentsD3D11 *attachments; michael@0: size = sizeof(attachments); michael@0: mDevice->GetPrivateData(sDeviceAttachmentsD3D11, &size, &attachments); michael@0: // No LayerManagers left for this device. Clear out interfaces stored michael@0: // which hold a reference to the device. michael@0: mDevice->SetPrivateData(sDeviceAttachmentsD3D11, 0, nullptr); michael@0: michael@0: delete attachments; michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool michael@0: CompositorD3D11::Initialize() michael@0: { michael@0: HRESULT hr; michael@0: michael@0: mDevice = gfxWindowsPlatform::GetPlatform()->GetD3D11Device(); michael@0: michael@0: if (!mDevice) { michael@0: return false; michael@0: } michael@0: michael@0: mDevice->GetImmediateContext(byRef(mContext)); michael@0: michael@0: if (!mContext) { michael@0: return false; michael@0: } michael@0: michael@0: mHwnd = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW); michael@0: michael@0: memset(&mVSConstants, 0, sizeof(VertexShaderConstants)); michael@0: michael@0: int referenceCount = 0; michael@0: UINT size = sizeof(referenceCount); michael@0: // If this isn't there yet it'll fail, count will remain 0, which is correct. michael@0: mDevice->GetPrivateData(sLayerManagerCount, &size, &referenceCount); michael@0: referenceCount++; michael@0: mDevice->SetPrivateData(sLayerManagerCount, michael@0: sizeof(referenceCount), michael@0: &referenceCount); michael@0: michael@0: size = sizeof(DeviceAttachmentsD3D11*); michael@0: if (FAILED(mDevice->GetPrivateData(sDeviceAttachmentsD3D11, michael@0: &size, michael@0: &mAttachments))) { michael@0: mAttachments = new DeviceAttachmentsD3D11; michael@0: mDevice->SetPrivateData(sDeviceAttachmentsD3D11, michael@0: sizeof(mAttachments), michael@0: &mAttachments); michael@0: michael@0: D3D11_INPUT_ELEMENT_DESC layout[] = michael@0: { michael@0: { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, michael@0: }; michael@0: michael@0: hr = mDevice->CreateInputLayout(layout, michael@0: sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC), michael@0: LayerQuadVS, michael@0: sizeof(LayerQuadVS), michael@0: byRef(mAttachments->mInputLayout)); michael@0: michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} }; michael@0: CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER); michael@0: D3D11_SUBRESOURCE_DATA data; michael@0: data.pSysMem = (void*)vertices; michael@0: michael@0: hr = mDevice->CreateBuffer(&bufferDesc, &data, byRef(mAttachments->mVertexBuffer)); michael@0: michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: if (!CreateShaders()) { michael@0: return false; michael@0: } michael@0: michael@0: CD3D11_BUFFER_DESC cBufferDesc(sizeof(VertexShaderConstants), michael@0: D3D11_BIND_CONSTANT_BUFFER, michael@0: D3D11_USAGE_DYNAMIC, michael@0: D3D11_CPU_ACCESS_WRITE); michael@0: michael@0: hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, byRef(mAttachments->mVSConstantBuffer)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: cBufferDesc.ByteWidth = sizeof(PixelShaderConstants); michael@0: hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, byRef(mAttachments->mPSConstantBuffer)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: CD3D11_RASTERIZER_DESC rastDesc(D3D11_DEFAULT); michael@0: rastDesc.CullMode = D3D11_CULL_NONE; michael@0: rastDesc.ScissorEnable = TRUE; michael@0: michael@0: hr = mDevice->CreateRasterizerState(&rastDesc, byRef(mAttachments->mRasterizerState)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT); michael@0: samplerDesc.AddressU = samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; michael@0: hr = mDevice->CreateSamplerState(&samplerDesc, byRef(mAttachments->mLinearSamplerState)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; michael@0: hr = mDevice->CreateSamplerState(&samplerDesc, byRef(mAttachments->mPointSamplerState)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: CD3D11_BLEND_DESC blendDesc(D3D11_DEFAULT); michael@0: D3D11_RENDER_TARGET_BLEND_DESC rtBlendPremul = { michael@0: TRUE, michael@0: D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, michael@0: D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, michael@0: D3D11_COLOR_WRITE_ENABLE_ALL michael@0: }; michael@0: blendDesc.RenderTarget[0] = rtBlendPremul; michael@0: hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mPremulBlendState)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: D3D11_RENDER_TARGET_BLEND_DESC rtBlendNonPremul = { michael@0: TRUE, michael@0: D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, michael@0: D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, michael@0: D3D11_COLOR_WRITE_ENABLE_ALL michael@0: }; michael@0: blendDesc.RenderTarget[0] = rtBlendNonPremul; michael@0: hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mNonPremulBlendState)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: if (gfxPrefs::ComponentAlphaEnabled()) { michael@0: D3D11_RENDER_TARGET_BLEND_DESC rtBlendComponent = { michael@0: TRUE, michael@0: D3D11_BLEND_ONE, michael@0: D3D11_BLEND_INV_SRC1_COLOR, michael@0: D3D11_BLEND_OP_ADD, michael@0: D3D11_BLEND_ONE, michael@0: D3D11_BLEND_INV_SRC_ALPHA, michael@0: D3D11_BLEND_OP_ADD, michael@0: D3D11_COLOR_WRITE_ENABLE_ALL michael@0: }; michael@0: blendDesc.RenderTarget[0] = rtBlendComponent; michael@0: hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mComponentBlendState)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: D3D11_RENDER_TARGET_BLEND_DESC rtBlendDisabled = { michael@0: FALSE, michael@0: D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, michael@0: D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, michael@0: D3D11_COLOR_WRITE_ENABLE_ALL michael@0: }; michael@0: blendDesc.RenderTarget[0] = rtBlendDisabled; michael@0: hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mDisabledBlendState)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: nsRefPtr dxgiDevice; michael@0: nsRefPtr dxgiAdapter; michael@0: michael@0: mDevice->QueryInterface(dxgiDevice.StartAssignment()); michael@0: dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)); michael@0: michael@0: #ifdef MOZ_METRO michael@0: if (IsRunningInWindowsMetro()) { michael@0: nsRefPtr dxgiFactory; michael@0: dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment())); michael@0: michael@0: nsIntRect rect; michael@0: mWidget->GetClientBounds(rect); michael@0: michael@0: DXGI_SWAP_CHAIN_DESC1 swapDesc = { 0 }; michael@0: // Automatically detect the width and the height from the winrt CoreWindow michael@0: swapDesc.Width = rect.width; michael@0: swapDesc.Height = rect.height; michael@0: // This is the most common swapchain format michael@0: swapDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; michael@0: swapDesc.Stereo = false; michael@0: // Don't use multi-sampling michael@0: swapDesc.SampleDesc.Count = 1; michael@0: swapDesc.SampleDesc.Quality = 0; michael@0: swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; michael@0: // Use double buffering to enable flip michael@0: swapDesc.BufferCount = 2; michael@0: swapDesc.Scaling = DXGI_SCALING_NONE; michael@0: // All Metro style apps must use this SwapEffect michael@0: swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; michael@0: swapDesc.Flags = 0; michael@0: michael@0: /** michael@0: * Create a swap chain, this swap chain will contain the backbuffer for michael@0: * the window we draw to. The front buffer is the full screen front michael@0: * buffer. michael@0: */ michael@0: nsRefPtr swapChain1; michael@0: hr = dxgiFactory->CreateSwapChainForCoreWindow( michael@0: dxgiDevice, (IUnknown *)mWidget->GetNativeData(NS_NATIVE_ICOREWINDOW), michael@0: &swapDesc, nullptr, getter_AddRefs(swapChain1)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: mSwapChain = swapChain1; michael@0: } else michael@0: #endif michael@0: { michael@0: nsRefPtr dxgiFactory; michael@0: dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment())); michael@0: michael@0: DXGI_SWAP_CHAIN_DESC swapDesc; michael@0: ::ZeroMemory(&swapDesc, sizeof(swapDesc)); michael@0: swapDesc.BufferDesc.Width = 0; michael@0: swapDesc.BufferDesc.Height = 0; michael@0: swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; michael@0: swapDesc.BufferDesc.RefreshRate.Numerator = 60; michael@0: swapDesc.BufferDesc.RefreshRate.Denominator = 1; michael@0: swapDesc.SampleDesc.Count = 1; michael@0: swapDesc.SampleDesc.Quality = 0; michael@0: swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; michael@0: swapDesc.BufferCount = 1; michael@0: swapDesc.OutputWindow = mHwnd; michael@0: swapDesc.Windowed = TRUE; michael@0: // We don't really need this flag, however it seems on some NVidia hardware michael@0: // smaller area windows do not present properly without this flag. This flag michael@0: // should have no negative consequences by itself. See bug 613790. This flag michael@0: // is broken on optimus devices. As a temporary solution we don't set it michael@0: // there, the only way of reliably detecting we're on optimus is looking for michael@0: // the DLL. See Bug 623807. michael@0: if (gfxWindowsPlatform::IsOptimus()) { michael@0: swapDesc.Flags = 0; michael@0: } else { michael@0: swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE; michael@0: } michael@0: michael@0: /** michael@0: * Create a swap chain, this swap chain will contain the backbuffer for michael@0: * the window we draw to. The front buffer is the full screen front michael@0: * buffer. michael@0: */ michael@0: hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, byRef(mSwapChain)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: // We need this because we don't want DXGI to respond to Alt+Enter. michael@0: dxgiFactory->MakeWindowAssociation(swapDesc.OutputWindow, michael@0: DXGI_MWA_NO_WINDOW_CHANGES); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorD3D11::CreateDataTextureSource(TextureFlags aFlags) michael@0: { michael@0: RefPtr result = new DataTextureSourceD3D11(gfx::SurfaceFormat::UNKNOWN, michael@0: this, aFlags); michael@0: return result.forget(); michael@0: } michael@0: michael@0: TextureFactoryIdentifier michael@0: CompositorD3D11::GetTextureFactoryIdentifier() michael@0: { michael@0: TextureFactoryIdentifier ident; michael@0: ident.mMaxTextureSize = GetMaxTextureSize(); michael@0: ident.mParentProcessId = XRE_GetProcessType(); michael@0: ident.mParentBackend = LayersBackend::LAYERS_D3D11; michael@0: return ident; michael@0: } michael@0: michael@0: bool michael@0: CompositorD3D11::CanUseCanvasLayerForSize(const gfx::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: CompositorD3D11::GetMaxTextureSize() const michael@0: { michael@0: return GetMaxTextureSizeForFeatureLevel(mFeatureLevel); michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorD3D11::CreateRenderTarget(const gfx::IntRect& aRect, michael@0: SurfaceInitMode aInit) michael@0: { michael@0: CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aRect.width, aRect.height, 1, 1, michael@0: D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); michael@0: michael@0: RefPtr texture; michael@0: mDevice->CreateTexture2D(&desc, nullptr, byRef(texture)); michael@0: NS_ASSERTION(texture, "Could not create texture"); michael@0: if (!texture) { michael@0: return nullptr; michael@0: } michael@0: michael@0: RefPtr rt = new CompositingRenderTargetD3D11(texture, aRect.TopLeft()); michael@0: rt->SetSize(IntSize(aRect.width, aRect.height)); michael@0: michael@0: if (aInit == INIT_MODE_CLEAR) { michael@0: FLOAT clear[] = { 0, 0, 0, 0 }; michael@0: mContext->ClearRenderTargetView(rt->mRTView, clear); michael@0: } michael@0: michael@0: return rt; michael@0: } michael@0: michael@0: TemporaryRef michael@0: CompositorD3D11::CreateRenderTargetFromSource(const gfx::IntRect &aRect, michael@0: const CompositingRenderTarget* aSource, michael@0: const gfx::IntPoint &aSourcePoint) michael@0: { michael@0: CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, michael@0: aRect.width, aRect.height, 1, 1, michael@0: D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); michael@0: michael@0: RefPtr texture; michael@0: mDevice->CreateTexture2D(&desc, nullptr, byRef(texture)); michael@0: NS_ASSERTION(texture, "Could not create texture"); michael@0: if (!texture) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (aSource) { michael@0: const CompositingRenderTargetD3D11* sourceD3D11 = michael@0: static_cast(aSource); michael@0: michael@0: D3D11_BOX srcBox; michael@0: srcBox.left = aSourcePoint.x; michael@0: srcBox.top = aSourcePoint.y; michael@0: srcBox.front = 0; michael@0: srcBox.right = aSourcePoint.x + aRect.width; michael@0: srcBox.bottom = aSourcePoint.y + aRect.height; michael@0: srcBox.back = 0; michael@0: michael@0: const IntSize& srcSize = sourceD3D11->GetSize(); michael@0: MOZ_ASSERT(srcSize.width >= 0 && srcSize.height >= 0, michael@0: "render targets should have nonnegative sizes"); michael@0: if (srcBox.right <= static_cast(srcSize.width) && michael@0: srcBox.bottom <= static_cast(srcSize.height)) { michael@0: mContext->CopySubresourceRegion(texture, 0, michael@0: 0, 0, 0, michael@0: sourceD3D11->GetD3D11Texture(), 0, michael@0: &srcBox); michael@0: } else { michael@0: NS_WARNING("Could not copy render target - source rect out of bounds"); michael@0: } michael@0: } michael@0: michael@0: RefPtr rt = michael@0: new CompositingRenderTargetD3D11(texture, aRect.TopLeft()); michael@0: rt->SetSize(aRect.Size()); michael@0: michael@0: return rt; michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::SetRenderTarget(CompositingRenderTarget* aRenderTarget) michael@0: { michael@0: MOZ_ASSERT(aRenderTarget); michael@0: CompositingRenderTargetD3D11* newRT = michael@0: static_cast(aRenderTarget); michael@0: ID3D11RenderTargetView* view = newRT->mRTView; michael@0: mCurrentRT = newRT; michael@0: mContext->OMSetRenderTargets(1, &view, nullptr); michael@0: PrepareViewport(newRT->GetSize(), gfx::Matrix()); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::SetPSForEffect(Effect* aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat) michael@0: { michael@0: switch (aEffect->mType) { michael@0: case EFFECT_SOLID_COLOR: michael@0: mContext->PSSetShader(mAttachments->mSolidColorShader[aMaskType], nullptr, 0); michael@0: return; michael@0: case EFFECT_RENDER_TARGET: michael@0: mContext->PSSetShader(mAttachments->mRGBAShader[aMaskType], nullptr, 0); michael@0: return; michael@0: case EFFECT_RGB: michael@0: mContext->PSSetShader((aFormat == SurfaceFormat::B8G8R8A8 || aFormat == SurfaceFormat::R8G8B8A8) michael@0: ? mAttachments->mRGBAShader[aMaskType] michael@0: : mAttachments->mRGBShader[aMaskType], nullptr, 0); michael@0: return; michael@0: case EFFECT_YCBCR: michael@0: mContext->PSSetShader(mAttachments->mYCbCrShader[aMaskType], nullptr, 0); michael@0: return; michael@0: case EFFECT_COMPONENT_ALPHA: michael@0: mContext->PSSetShader(mAttachments->mComponentAlphaShader[aMaskType], nullptr, 0); michael@0: return; michael@0: default: michael@0: NS_WARNING("No shader to load"); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::ClearRect(const gfx::Rect& aRect) michael@0: { michael@0: mContext->OMSetBlendState(mAttachments->mDisabledBlendState, sBlendFactor, 0xFFFFFFFF); michael@0: michael@0: Matrix4x4 identity; michael@0: memcpy(&mVSConstants.layerTransform, &identity._11, 64); michael@0: michael@0: mVSConstants.layerQuad = aRect; michael@0: mVSConstants.renderTargetOffset[0] = 0; michael@0: mVSConstants.renderTargetOffset[1] = 0; michael@0: mPSConstants.layerOpacity[0] = 1.0f; michael@0: michael@0: D3D11_RECT scissor; michael@0: scissor.left = aRect.x; michael@0: scissor.right = aRect.XMost(); michael@0: scissor.top = aRect.y; michael@0: scissor.bottom = aRect.YMost(); michael@0: mContext->RSSetScissorRects(1, &scissor); michael@0: mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); michael@0: mContext->VSSetShader(mAttachments->mVSQuadShader[MaskNone], nullptr, 0); michael@0: michael@0: mContext->PSSetShader(mAttachments->mSolidColorShader[MaskNone], nullptr, 0); michael@0: mPSConstants.layerColor[0] = 0; michael@0: mPSConstants.layerColor[1] = 0; michael@0: mPSConstants.layerColor[2] = 0; michael@0: mPSConstants.layerColor[3] = 0; michael@0: michael@0: UpdateConstantBuffers(); michael@0: michael@0: mContext->Draw(4, 0); michael@0: michael@0: mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::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: MOZ_ASSERT(mCurrentRT, "No render target"); michael@0: memcpy(&mVSConstants.layerTransform, &aTransform._11, 64); michael@0: IntPoint origin = mCurrentRT->GetOrigin(); michael@0: mVSConstants.renderTargetOffset[0] = origin.x; michael@0: mVSConstants.renderTargetOffset[1] = origin.y; michael@0: mVSConstants.layerQuad = aRect; michael@0: michael@0: mPSConstants.layerOpacity[0] = aOpacity; michael@0: michael@0: bool restoreBlendMode = false; 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: MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EFFECT_RGB); michael@0: maskType = Mask3d; michael@0: } michael@0: michael@0: EffectMask* maskEffect = michael@0: static_cast(aEffectChain.mSecondaryEffects[EFFECT_MASK].get()); michael@0: TextureSourceD3D11* source = maskEffect->mMaskTexture->AsSourceD3D11(); michael@0: michael@0: if (!source) { michael@0: NS_WARNING("Missing texture source!"); michael@0: return; michael@0: } michael@0: michael@0: RefPtr view; michael@0: mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view)); michael@0: michael@0: ID3D11ShaderResourceView* srView = view; michael@0: mContext->PSSetShaderResources(3, 1, &srView); 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: michael@0: mVSConstants.maskQuad = maskTransform.As2D().TransformBounds(bounds); michael@0: } michael@0: michael@0: michael@0: D3D11_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: mContext->RSSetScissorRects(1, &scissor); michael@0: mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); michael@0: mContext->VSSetShader(mAttachments->mVSQuadShader[maskType], nullptr, 0); michael@0: michael@0: michael@0: switch (aEffectChain.mPrimaryEffect->mType) { michael@0: case EFFECT_SOLID_COLOR: { michael@0: SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, SurfaceFormat::UNKNOWN); michael@0: michael@0: Color color = michael@0: static_cast(aEffectChain.mPrimaryEffect.get())->mColor; michael@0: mPSConstants.layerColor[0] = color.r * color.a * aOpacity; michael@0: mPSConstants.layerColor[1] = color.g * color.a * aOpacity; michael@0: mPSConstants.layerColor[2] = color.b * color.a * aOpacity; michael@0: mPSConstants.layerColor[3] = color.a * aOpacity; michael@0: } michael@0: break; michael@0: case EFFECT_RGB: michael@0: case EFFECT_RENDER_TARGET: michael@0: { michael@0: TexturedEffect* texturedEffect = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: michael@0: mVSConstants.textureCoords = texturedEffect->mTextureCoords; michael@0: michael@0: TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11(); michael@0: michael@0: if (!source) { michael@0: NS_WARNING("Missing texture source!"); michael@0: return; michael@0: } michael@0: michael@0: SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, texturedEffect->mTexture->GetFormat()); michael@0: michael@0: RefPtr view; michael@0: mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view)); michael@0: michael@0: ID3D11ShaderResourceView* srView = view; michael@0: mContext->PSSetShaderResources(0, 1, &srView); michael@0: michael@0: if (!texturedEffect->mPremultiplied) { michael@0: mContext->OMSetBlendState(mAttachments->mNonPremulBlendState, sBlendFactor, 0xFFFFFFFF); michael@0: restoreBlendMode = true; michael@0: } michael@0: michael@0: SetSamplerForFilter(texturedEffect->mFilter); michael@0: } michael@0: break; michael@0: case EFFECT_YCBCR: { michael@0: EffectYCbCr* ycbcrEffect = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: michael@0: SetSamplerForFilter(Filter::LINEAR); michael@0: michael@0: mVSConstants.textureCoords = ycbcrEffect->mTextureCoords; 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: SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, ycbcrEffect->mTexture->GetFormat()); 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: TextureSourceD3D11* sourceY = source->GetSubSource(Y)->AsSourceD3D11(); michael@0: TextureSourceD3D11* sourceCb = source->GetSubSource(Cb)->AsSourceD3D11(); michael@0: TextureSourceD3D11* sourceCr = source->GetSubSource(Cr)->AsSourceD3D11(); michael@0: michael@0: RefPtr views[3]; michael@0: mDevice->CreateShaderResourceView(sourceY->GetD3D11Texture(), michael@0: nullptr, byRef(views[0])); michael@0: mDevice->CreateShaderResourceView(sourceCb->GetD3D11Texture(), michael@0: nullptr, byRef(views[1])); michael@0: mDevice->CreateShaderResourceView(sourceCr->GetD3D11Texture(), michael@0: nullptr, byRef(views[2])); michael@0: michael@0: ID3D11ShaderResourceView* srViews[3] = { views[0], views[1], views[2] }; michael@0: mContext->PSSetShaderResources(0, 3, srViews); michael@0: } michael@0: break; michael@0: case EFFECT_COMPONENT_ALPHA: michael@0: { michael@0: MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled()); michael@0: MOZ_ASSERT(mAttachments->mComponentBlendState); michael@0: EffectComponentAlpha* effectComponentAlpha = michael@0: static_cast(aEffectChain.mPrimaryEffect.get()); michael@0: michael@0: TextureSourceD3D11* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D11(); michael@0: TextureSourceD3D11* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D11(); michael@0: michael@0: if (!sourceOnWhite || !sourceOnBlack) { michael@0: NS_WARNING("Missing texture source(s)!"); michael@0: return; michael@0: } michael@0: michael@0: SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, effectComponentAlpha->mOnWhite->GetFormat()); michael@0: michael@0: SetSamplerForFilter(effectComponentAlpha->mFilter); michael@0: michael@0: mVSConstants.textureCoords = effectComponentAlpha->mTextureCoords; michael@0: RefPtr views[2]; michael@0: mDevice->CreateShaderResourceView(sourceOnBlack->GetD3D11Texture(), nullptr, byRef(views[0])); michael@0: mDevice->CreateShaderResourceView(sourceOnWhite->GetD3D11Texture(), nullptr, byRef(views[1])); michael@0: michael@0: ID3D11ShaderResourceView* srViews[2] = { views[0], views[1] }; michael@0: mContext->PSSetShaderResources(0, 2, srViews); michael@0: michael@0: mContext->OMSetBlendState(mAttachments->mComponentBlendState, sBlendFactor, 0xFFFFFFFF); michael@0: restoreBlendMode = true; michael@0: } michael@0: break; michael@0: default: michael@0: NS_WARNING("Unknown shader type"); michael@0: return; michael@0: } michael@0: UpdateConstantBuffers(); michael@0: michael@0: mContext->Draw(4, 0); michael@0: if (restoreBlendMode) { michael@0: mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::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: // Don't composite if we are minimised. Other than for the sake of efficency, michael@0: // this is important because resizing our buffers when mimised will fail and michael@0: // cause a crash when we're restored. michael@0: NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?"); michael@0: if (::IsIconic(mHwnd)) { michael@0: *aRenderBoundsOut = Rect(); michael@0: return; michael@0: } michael@0: michael@0: UpdateRenderTarget(); michael@0: michael@0: // Failed to create a render target or the view. michael@0: if (!mDefaultRT || !mDefaultRT->mRTView || michael@0: mSize.width == 0 || mSize.height == 0) { michael@0: *aRenderBoundsOut = Rect(); michael@0: return; michael@0: } michael@0: michael@0: mContext->IASetInputLayout(mAttachments->mInputLayout); michael@0: michael@0: ID3D11Buffer* buffer = mAttachments->mVertexBuffer; michael@0: UINT size = sizeof(Vertex); michael@0: UINT offset = 0; michael@0: mContext->IASetVertexBuffers(0, 1, &buffer, &size, &offset); 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: D3D11_RECT scissor; michael@0: if (aClipRectIn) { michael@0: scissor.left = aClipRectIn->x; michael@0: scissor.right = aClipRectIn->XMost(); michael@0: scissor.top = aClipRectIn->y; michael@0: scissor.bottom = aClipRectIn->YMost(); michael@0: } else { michael@0: scissor.left = scissor.top = 0; michael@0: scissor.right = mSize.width; michael@0: scissor.bottom = mSize.height; michael@0: } michael@0: mContext->RSSetScissorRects(1, &scissor); michael@0: michael@0: FLOAT black[] = { 0, 0, 0, 0 }; michael@0: mContext->ClearRenderTargetView(mDefaultRT->mRTView, black); michael@0: michael@0: mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF); michael@0: mContext->RSSetState(mAttachments->mRasterizerState); michael@0: michael@0: SetRenderTarget(mDefaultRT); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::EndFrame() michael@0: { michael@0: mContext->Flush(); michael@0: michael@0: nsIntSize oldSize = mSize; michael@0: EnsureSize(); michael@0: if (oldSize == mSize) { michael@0: mSwapChain->Present(0, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0); michael@0: mDisableSequenceForNextFrame = false; michael@0: if (mTarget) { michael@0: PaintToTarget(); michael@0: } michael@0: } michael@0: michael@0: mCurrentRT = nullptr; michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::PrepareViewport(const gfx::IntSize& aSize, michael@0: const gfx::Matrix& aWorldTransform) michael@0: { michael@0: D3D11_VIEWPORT viewport; michael@0: viewport.MaxDepth = 1.0f; michael@0: viewport.MinDepth = 0; michael@0: viewport.Width = aSize.width; michael@0: viewport.Height = aSize.height; michael@0: viewport.TopLeftX = 0; michael@0: viewport.TopLeftY = 0; michael@0: michael@0: mContext->RSSetViewports(1, &viewport); michael@0: michael@0: Matrix viewMatrix; michael@0: viewMatrix.Translate(-1.0, 1.0); michael@0: viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height)); michael@0: viewMatrix.Scale(1.0f, -1.0f); michael@0: michael@0: viewMatrix = aWorldTransform * viewMatrix; michael@0: michael@0: Matrix4x4 projection = Matrix4x4::From2D(viewMatrix); michael@0: projection._33 = 0.0f; michael@0: michael@0: memcpy(&mVSConstants.projection, &projection, sizeof(mVSConstants.projection)); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::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: CompositorD3D11::VerifyBufferSize() michael@0: { michael@0: DXGI_SWAP_CHAIN_DESC swapDesc; michael@0: mSwapChain->GetDesc(&swapDesc); michael@0: michael@0: if ((swapDesc.BufferDesc.Width == mSize.width && michael@0: swapDesc.BufferDesc.Height == mSize.height) || michael@0: mSize.width == 0 || mSize.height == 0) { michael@0: return; michael@0: } michael@0: michael@0: mDefaultRT = nullptr; michael@0: michael@0: if (IsRunningInWindowsMetro()) { michael@0: mSwapChain->ResizeBuffers(2, mSize.width, mSize.height, michael@0: DXGI_FORMAT_B8G8R8A8_UNORM, michael@0: 0); michael@0: mDisableSequenceForNextFrame = true; michael@0: } else if (gfxWindowsPlatform::IsOptimus()) { michael@0: mSwapChain->ResizeBuffers(1, mSize.width, mSize.height, michael@0: DXGI_FORMAT_B8G8R8A8_UNORM, michael@0: 0); michael@0: } else { michael@0: mSwapChain->ResizeBuffers(1, mSize.width, mSize.height, michael@0: DXGI_FORMAT_B8G8R8A8_UNORM, michael@0: DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE); michael@0: } michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::UpdateRenderTarget() michael@0: { michael@0: EnsureSize(); michael@0: VerifyBufferSize(); michael@0: michael@0: if (mDefaultRT) { michael@0: return; michael@0: } michael@0: michael@0: HRESULT hr; michael@0: michael@0: nsRefPtr backBuf; michael@0: michael@0: hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuf.StartAssignment()); michael@0: if (FAILED(hr)) { michael@0: return; michael@0: } michael@0: michael@0: mDefaultRT = new CompositingRenderTargetD3D11(backBuf, IntPoint(0, 0)); michael@0: mDefaultRT->SetSize(mSize.ToIntSize()); michael@0: } michael@0: michael@0: bool michael@0: CompositorD3D11::CreateShaders() michael@0: { michael@0: HRESULT hr; michael@0: michael@0: hr = mDevice->CreateVertexShader(LayerQuadVS, michael@0: sizeof(LayerQuadVS), michael@0: nullptr, michael@0: byRef(mAttachments->mVSQuadShader[MaskNone])); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: hr = mDevice->CreateVertexShader(LayerQuadMaskVS, michael@0: sizeof(LayerQuadMaskVS), michael@0: nullptr, michael@0: byRef(mAttachments->mVSQuadShader[Mask2d])); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: hr = mDevice->CreateVertexShader(LayerQuadMask3DVS, michael@0: sizeof(LayerQuadMask3DVS), michael@0: nullptr, michael@0: byRef(mAttachments->mVSQuadShader[Mask3d])); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: #define LOAD_PIXEL_SHADER(x) hr = mDevice->CreatePixelShader(x, sizeof(x), nullptr, byRef(mAttachments->m##x[MaskNone])); \ michael@0: if (FAILED(hr)) { \ michael@0: return false; \ michael@0: } \ michael@0: hr = mDevice->CreatePixelShader(x##Mask, sizeof(x##Mask), nullptr, byRef(mAttachments->m##x[Mask2d])); \ michael@0: if (FAILED(hr)) { \ michael@0: return false; \ michael@0: } michael@0: michael@0: LOAD_PIXEL_SHADER(SolidColorShader); michael@0: LOAD_PIXEL_SHADER(RGBShader); michael@0: LOAD_PIXEL_SHADER(RGBAShader); michael@0: LOAD_PIXEL_SHADER(YCbCrShader); michael@0: if (gfxPrefs::ComponentAlphaEnabled()) { michael@0: LOAD_PIXEL_SHADER(ComponentAlphaShader); michael@0: } michael@0: michael@0: #undef LOAD_PIXEL_SHADER michael@0: michael@0: hr = mDevice->CreatePixelShader(RGBAShaderMask3D, michael@0: sizeof(RGBAShaderMask3D), michael@0: nullptr, michael@0: byRef(mAttachments->mRGBAShader[Mask3d])); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::UpdateConstantBuffers() michael@0: { michael@0: D3D11_MAPPED_SUBRESOURCE resource; michael@0: mContext->Map(mAttachments->mVSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); michael@0: *(VertexShaderConstants*)resource.pData = mVSConstants; michael@0: mContext->Unmap(mAttachments->mVSConstantBuffer, 0); michael@0: mContext->Map(mAttachments->mPSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); michael@0: *(PixelShaderConstants*)resource.pData = mPSConstants; michael@0: mContext->Unmap(mAttachments->mPSConstantBuffer, 0); michael@0: michael@0: ID3D11Buffer *buffer = mAttachments->mVSConstantBuffer; michael@0: michael@0: mContext->VSSetConstantBuffers(0, 1, &buffer); michael@0: michael@0: buffer = mAttachments->mPSConstantBuffer; michael@0: mContext->PSSetConstantBuffers(0, 1, &buffer); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::SetSamplerForFilter(Filter aFilter) michael@0: { michael@0: ID3D11SamplerState *sampler; michael@0: switch (aFilter) { michael@0: default: michael@0: case Filter::LINEAR: michael@0: sampler = mAttachments->mLinearSamplerState; michael@0: break; michael@0: case Filter::POINT: michael@0: sampler = mAttachments->mPointSamplerState; michael@0: break; michael@0: } michael@0: michael@0: mContext->PSSetSamplers(0, 1, &sampler); michael@0: } michael@0: michael@0: void michael@0: CompositorD3D11::PaintToTarget() michael@0: { michael@0: nsRefPtr backBuf; michael@0: michael@0: mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuf.StartAssignment()); michael@0: michael@0: D3D11_TEXTURE2D_DESC bbDesc; michael@0: backBuf->GetDesc(&bbDesc); michael@0: michael@0: CD3D11_TEXTURE2D_DESC softDesc(bbDesc.Format, bbDesc.Width, bbDesc.Height); michael@0: softDesc.MipLevels = 1; michael@0: softDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; michael@0: softDesc.Usage = D3D11_USAGE_STAGING; michael@0: softDesc.BindFlags = 0; michael@0: michael@0: nsRefPtr readTexture; michael@0: michael@0: HRESULT hr = mDevice->CreateTexture2D(&softDesc, nullptr, getter_AddRefs(readTexture)); michael@0: mContext->CopyResource(readTexture, backBuf); michael@0: michael@0: D3D11_MAPPED_SUBRESOURCE map; michael@0: mContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &map); michael@0: RefPtr sourceSurface = michael@0: Factory::CreateWrappingDataSourceSurface((uint8_t*)map.pData, michael@0: map.RowPitch, michael@0: IntSize(bbDesc.Width, bbDesc.Height), michael@0: SurfaceFormat::B8G8R8A8); michael@0: mTarget->CopySurface(sourceSurface, michael@0: IntRect(0, 0, bbDesc.Width, bbDesc.Height), michael@0: IntPoint()); michael@0: mTarget->Flush(); michael@0: mContext->Unmap(readTexture, 0); michael@0: } michael@0: michael@0: } michael@0: }