diff --git a/gfx/layers/Makefile.in b/gfx/layers/Makefile.in index 2f397ca3023..9ea382af17e 100644 --- a/gfx/layers/Makefile.in +++ b/gfx/layers/Makefile.in @@ -84,7 +84,10 @@ CPPSRCS = \ ifeq ($(MOZ_WIDGET_TOOLKIT),windows) ifdef MOZ_ENABLE_D3D9_LAYER -EXPORTS += LayerManagerD3D9.h +EXPORTS += \ + LayerManagerD3D9.h \ + DeviceManagerD3D9.h \ + $(NULL) CPPSRCS += \ LayerManagerD3D9.cpp \ @@ -93,6 +96,7 @@ CPPSRCS += \ ImageLayerD3D9.cpp \ ColorLayerD3D9.cpp \ CanvasLayerD3D9.cpp \ + DeviceManagerD3D9.cpp \ $(NULL) endif endif diff --git a/gfx/layers/d3d9/CanvasLayerD3D9.cpp b/gfx/layers/d3d9/CanvasLayerD3D9.cpp index 976d3a82eb6..756f373e01e 100644 --- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp +++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp @@ -230,7 +230,7 @@ CanvasLayerD3D9::RenderLayer() opacity[0] = GetOpacity(); device()->SetPixelShaderConstantF(0, opacity, 1); - mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER); + mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER); if (!mGLBufferIsPremultiplied) { device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); diff --git a/gfx/layers/d3d9/ColorLayerD3D9.cpp b/gfx/layers/d3d9/ColorLayerD3D9.cpp index ad7fde80292..a1f7d12db55 100644 --- a/gfx/layers/d3d9/ColorLayerD3D9.cpp +++ b/gfx/layers/d3d9/ColorLayerD3D9.cpp @@ -76,7 +76,7 @@ ColorLayerD3D9::RenderLayer() device()->SetPixelShaderConstantF(0, color, 1); - mD3DManager->SetShaderMode(LayerManagerD3D9::SOLIDCOLORLAYER); + mD3DManager->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } diff --git a/gfx/layers/d3d9/ContainerLayerD3D9.cpp b/gfx/layers/d3d9/ContainerLayerD3D9.cpp index f2f3f8fef40..8f1b2a708b4 100644 --- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp +++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp @@ -254,7 +254,7 @@ ContainerLayerD3D9::RenderLayer() opacityVector[0] = opacity; device()->SetPixelShaderConstantF(0, opacityVector, 1); - mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER); + mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER); device()->SetTexture(0, renderTexture); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); diff --git a/gfx/layers/d3d9/DeviceManagerD3D9.cpp b/gfx/layers/d3d9/DeviceManagerD3D9.cpp new file mode 100644 index 00000000000..90573dce4c0 --- /dev/null +++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp @@ -0,0 +1,480 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "DeviceManagerD3D9.h" +#include "LayerManagerD3D9Shaders.h" +#include "ThebesLayerD3D9.h" +#include "nsIServiceManager.h" +#include "nsIConsoleService.h" +#include "nsPrintfCString.h" + +namespace mozilla { +namespace layers { + +const LPCWSTR kClassName = L"D3D9WindowClass"; + +typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)( + UINT SDKVersion +); + +struct vertex { + float x, y; +}; + +SwapChainD3D9::SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager) + : mDeviceManager(aDeviceManager) + , mWnd(0) +{ + mDeviceManager->mSwapChains.AppendElement(this); +} + +SwapChainD3D9::~SwapChainD3D9() +{ + mDeviceManager->mSwapChains.RemoveElement(this); +} + +bool +SwapChainD3D9::Init(HWND hWnd) +{ + RECT r; + ::GetClientRect(hWnd, &r); + + mWnd = hWnd; + + D3DPRESENT_PARAMETERS pp; + memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); + + pp.BackBufferFormat = D3DFMT_UNKNOWN; + pp.SwapEffect = D3DSWAPEFFECT_COPY; + pp.Windowed = TRUE; + pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + pp.hDeviceWindow = mWnd; + if (r.left == r.right || r.top == r.bottom) { + pp.BackBufferHeight = 1; + pp.BackBufferWidth = 1; + } + + HRESULT hr = mDeviceManager->device()-> + CreateAdditionalSwapChain(&pp, + getter_AddRefs(mSwapChain)); + + if (FAILED(hr)) { + NS_WARNING("Failed to create swap chain for window."); + return false; + } + + return true; +} + +bool +SwapChainD3D9::PrepareForRendering() +{ + RECT r; + if (!::GetClientRect(mWnd, &r)) { + return false; + } + + if (!mDeviceManager->VerifyReadyForRendering()) { + return false; + } + + if (!mSwapChain) { + Init(mWnd); + } + + if (mSwapChain) { + nsRefPtr backBuffer; + mSwapChain->GetBackBuffer(0, + D3DBACKBUFFER_TYPE_MONO, + getter_AddRefs(backBuffer)); + + D3DSURFACE_DESC desc; + backBuffer->GetDesc(&desc); + + if (desc.Width == r.right - r.left && desc.Height == r.bottom - r.top) { + mDeviceManager->device()->SetRenderTarget(0, backBuffer); + return true; + } + + mSwapChain = nsnull; + + Init(mWnd); + + if (!mSwapChain) { + return false; + } + + mSwapChain->GetBackBuffer(0, + D3DBACKBUFFER_TYPE_MONO, + getter_AddRefs(backBuffer)); + + mDeviceManager->device()->SetRenderTarget(0, backBuffer); + + return true; + } + return false; +} + +void +SwapChainD3D9::Present(const nsIntRect &aRect) +{ + RECT r; + r.left = aRect.x; + r.top = aRect.y; + r.right = aRect.XMost(); + r.bottom = aRect.YMost(); + + mSwapChain->Present(&r, &r, 0, 0, 0); +} + +void +SwapChainD3D9::Reset() +{ + mSwapChain = nsnull; +} + +#define HAS_CAP(a, b) (((a) & (b)) == (b)) +#define LACKS_CAP(a, b) !(((a) & (b)) == (b)) + +DeviceManagerD3D9::DeviceManagerD3D9() +{ +} + +bool +DeviceManagerD3D9::Init() +{ + WNDCLASSW wc; + if (!GetClassInfoW(GetModuleHandle(NULL), kClassName, &wc)) { + ZeroMemory(&wc, sizeof(WNDCLASSW)); + wc.hInstance = GetModuleHandle(NULL); + wc.lpfnWndProc = ::DefWindowProc; + wc.lpszClassName = kClassName; + if (!RegisterClassW(&wc)) { + NS_WARNING("Failed to register window class for DeviceManager."); + return false; + } + } + + mFocusWnd = CreateWindow(kClassName, L"D3D9Window", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, + NULL, GetModuleHandle(NULL), NULL); + + if (!mFocusWnd) { + NS_WARNING("Failed to create DeviceManagerD3D9 Window."); + return false; + } + + Direct3DCreate9Func d3d9create = (Direct3DCreate9Func) + GetProcAddress(LoadLibraryW(L"d3d9.dll"), "Direct3DCreate9"); + + if (!d3d9create) { + return false; + } + + mD3D9 = dont_AddRef(d3d9create(D3D_SDK_VERSION)); + + D3DPRESENT_PARAMETERS pp; + memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); + + pp.BackBufferWidth = 1; + pp.BackBufferHeight = 1; + pp.BackBufferFormat = D3DFMT_A8R8G8B8; + pp.SwapEffect = D3DSWAPEFFECT_DISCARD; + pp.Windowed = TRUE; + pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + pp.hDeviceWindow = mFocusWnd; + + HRESULT hr = mD3D9->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + mFocusWnd, + D3DCREATE_FPU_PRESERVE | + D3DCREATE_MULTITHREADED | + D3DCREATE_MIXED_VERTEXPROCESSING, + &pp, + getter_AddRefs(mDevice)); + + if (FAILED(hr)) { + NS_WARNING("Failed to create Device for DeviceManagerD3D9."); + return false; + } + + if (!VerifyCaps()) { + return false; + } + + hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS, + getter_AddRefs(mLayerVS)); + + if (FAILED(hr)) { + return false; + } + + hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPS, + getter_AddRefs(mRGBPS)); + + if (FAILED(hr)) { + return false; + } + + hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPS, + getter_AddRefs(mYCbCrPS)); + + if (FAILED(hr)) { + return false; + } + + hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPS, + getter_AddRefs(mSolidColorPS)); + + if (FAILED(hr)) { + return false; + } + + hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4, + 0, + 0, + D3DPOOL_MANAGED, + getter_AddRefs(mVB), + NULL); + + if (FAILED(hr)) { + return false; + } + + vertex *vertices; + hr = mVB->Lock(0, 0, (void**)&vertices, 0); + if (FAILED(hr)) { + return false; + } + + vertices[0].x = vertices[0].y = 0; + vertices[1].x = 1; vertices[1].y = 0; + vertices[2].x = 0; vertices[2].y = 1; + vertices[3].x = 1; vertices[3].y = 1; + + mVB->Unlock(); + + hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex)); + if (FAILED(hr)) { + return false; + } + + D3DVERTEXELEMENT9 elements[] = { + { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, + D3DDECLUSAGE_POSITION, 0 }, + D3DDECL_END() + }; + + mDevice->CreateVertexDeclaration(elements, getter_AddRefs(mVD)); + + nsCOMPtr + console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); + + D3DADAPTER_IDENTIFIER9 identifier; + mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier); + + if (console) { + nsString msg; + msg += + NS_LITERAL_STRING("Direct3D 9 DeviceManager Initialized Succesfully.\nDriver: "); + msg += NS_ConvertUTF8toUTF16( + nsDependentCString((const char*)identifier.Driver)); + msg += NS_LITERAL_STRING("\nDescription: "); + msg += NS_ConvertUTF8toUTF16( + nsDependentCString((const char*)identifier.Description)); + msg += NS_LITERAL_STRING("\nVersion: "); + msg += NS_ConvertUTF8toUTF16( + nsPrintfCString("%d.%d.%d.%d", + HIWORD(identifier.DriverVersion.HighPart), + LOWORD(identifier.DriverVersion.HighPart), + HIWORD(identifier.DriverVersion.LowPart), + LOWORD(identifier.DriverVersion.LowPart))); + console->LogStringMessage(msg.get()); + } + + return true; +} + +void +DeviceManagerD3D9::SetupRenderState() +{ + mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex)); + mDevice->SetVertexDeclaration(mVD); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); +} + +already_AddRefed +DeviceManagerD3D9::CreateSwapChain(HWND hWnd) +{ + nsRefPtr swapChain = new SwapChainD3D9(this); + + if (!swapChain->Init(hWnd)) { + return nsnull; + } + + return swapChain.forget(); +} + +void +DeviceManagerD3D9::SetShaderMode(ShaderMode aMode) +{ + switch (aMode) { + case RGBLAYER: + mDevice->SetVertexShader(mLayerVS); + mDevice->SetPixelShader(mRGBPS); + break; + case YCBCRLAYER: + mDevice->SetVertexShader(mLayerVS); + mDevice->SetPixelShader(mYCbCrPS); + break; + case SOLIDCOLORLAYER: + mDevice->SetVertexShader(mLayerVS); + mDevice->SetPixelShader(mSolidColorPS); + break; + } +} + +bool +DeviceManagerD3D9::VerifyReadyForRendering() +{ + HRESULT hr = mDevice->TestCooperativeLevel(); + + if (SUCCEEDED(hr)) { + return true; + } + + if (hr != D3DERR_DEVICENOTRESET) { + return false; + } + + for(unsigned int i = 0; i < mThebesLayers.Length(); i++) { + mThebesLayers[i]->CleanResources(); + } + for(unsigned int i = 0; i < mSwapChains.Length(); i++) { + mSwapChains[i]->Reset(); + } + + D3DPRESENT_PARAMETERS pp; + memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); + + pp.BackBufferWidth = 1; + pp.BackBufferHeight = 1; + pp.BackBufferFormat = D3DFMT_A8R8G8B8; + pp.SwapEffect = D3DSWAPEFFECT_DISCARD; + pp.Windowed = TRUE; + pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + pp.hDeviceWindow = mFocusWnd; + + hr = mDevice->Reset(&pp); + + if (FAILED(hr)) { + return false; + } + + return true; +} + +bool +DeviceManagerD3D9::VerifyCaps() +{ + D3DCAPS9 caps; + HRESULT hr = mDevice->GetDeviceCaps(&caps); + + if (FAILED(hr)) { + return false; + } + + if (LACKS_CAP(caps.DevCaps, D3DDEVCAPS_TEXTUREVIDEOMEMORY)) { + return false; + } + + if (LACKS_CAP(caps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE)) { + return false; + } + + if (LACKS_CAP(caps.SrcBlendCaps, D3DPBLENDCAPS_ONE) || + LACKS_CAP(caps.SrcBlendCaps, D3DBLEND_SRCALPHA) || + LACKS_CAP(caps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA)) { + return false; + } + + if (LACKS_CAP(caps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST)) { + return false; + } + + if (LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_ALPHA) || + HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_SQUAREONLY) || + (HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_POW2) && + LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL))) { + return false; + } + + if (LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MAGFLINEAR) || + LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MINFLINEAR)) { + return false; + } + + if (LACKS_CAP(caps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP)) { + return false; + } + + if (caps.MaxTextureHeight < 4096 || + caps.MaxTextureWidth < 4096) { + return false; + } + + if ((caps.PixelShaderVersion & 0xffff) < 0x200 || + (caps.VertexShaderVersion & 0xffff) < 0x200) { + return false; + } + + return true; +} + +} /* namespace layers */ +} /* namespace mozilla */ diff --git a/gfx/layers/d3d9/DeviceManagerD3D9.h b/gfx/layers/d3d9/DeviceManagerD3D9.h new file mode 100644 index 00000000000..ae92fa651b2 --- /dev/null +++ b/gfx/layers/d3d9/DeviceManagerD3D9.h @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_DEVICEMANAGERD3D9_H +#define GFX_DEVICEMANAGERD3D9_H + +#include "gfxTypes.h" +#include "nsRect.h" +#include "nsAutoPtr.h" +#include "d3d9.h" +#include "nsTArray.h" + +namespace mozilla { +namespace layers { + +class DeviceManagerD3D9; +class ThebesLayerD3D9; + +/** + * SwapChain class, this class manages the swap chain belonging to a + * LayerManagerD3D9. + */ +class THEBES_API SwapChainD3D9 +{ + NS_INLINE_DECL_REFCOUNTING(SwapChainD3D9) +public: + ~SwapChainD3D9(); + + /** + * This function will prepare the device this swap chain belongs to for + * rendering to this swap chain. Only after calling this function can the + * swap chain be drawn to, and only until this function is called on another + * swap chain belonging to this device will the device draw to it. Passed in + * is the size of the swap chain. If the window size differs from the size + * during the last call to this function the swap chain will resize. Note that + * in no case does this function guarantee the backbuffer to still have its + * old content. + */ + bool PrepareForRendering(); + + /** + * This function will present the selected rectangle of the swap chain to + * its associated window. + */ + void Present(const nsIntRect &aRect); + +private: + friend class DeviceManagerD3D9; + + SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager); + + bool Init(HWND hWnd); + + /** + * This causes us to release our swap chain, clearing out our resource usage + * so the master device may reset. + */ + void Reset(); + + nsRefPtr mSwapChain; + nsRefPtr mDeviceManager; + HWND mWnd; +}; + +/** + * Device manager, this class is used by the layer managers to share the D3D9 + * device and create swap chains for the individual windows the layer managers + * belong to. + */ +class THEBES_API DeviceManagerD3D9 +{ +public: + DeviceManagerD3D9(); + + // We want the nsrefcnt return value. So we cannot use the inline refcnt macro + NS_IMPL_ADDREF(DeviceManagerD3D9) + NS_IMPL_RELEASE(DeviceManagerD3D9) + + bool Init(); + + /** + * Sets up the render state for the device for layer rendering. + */ + void SetupRenderState(); + + /** + * Create a swap chain setup to work with the specified window. + */ + already_AddRefed CreateSwapChain(HWND hWnd); + + IDirect3DDevice9 *device() { return mDevice; } + + enum ShaderMode { + RGBLAYER, + YCBCRLAYER, + SOLIDCOLORLAYER + }; + + void SetShaderMode(ShaderMode aMode); + + /** + * We keep a list of all thebes layers since we need their D3DPOOL_DEFAULT + * surfaces to be released when we want to reset the device. + */ + nsTArray mThebesLayers; +private: + friend class SwapChainD3D9; + + /** + * This function verifies the device is ready for rendering, internally this + * will test the cooperative level of the device and reset the device if + * needed. If this returns false subsequent rendering calls may return errors. + */ + bool VerifyReadyForRendering(); + + /* Array used to store all swap chains for device resets */ + nsTArray mSwapChains; + + /* The D3D device we use */ + nsRefPtr mDevice; + + /* An instance of the D3D9 object */ + nsRefPtr mD3D9; + + /* Vertex shader used for layer quads */ + nsRefPtr mLayerVS; + + /* Pixel shader used for RGB textures */ + nsRefPtr mRGBPS; + + /* Pixel shader used for RGB textures */ + nsRefPtr mYCbCrPS; + + /* Pixel shader used for solid colors */ + nsRefPtr mSolidColorPS; + + /* Vertex buffer containing our basic vertex structure */ + nsRefPtr mVB; + + /* Our vertex declaration */ + nsRefPtr mVD; + + /* Our focus window - this is really a dummy window we can associate our + * device with. + */ + HWND mFocusWnd; + + nsAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD + + /** + * Verifies all required device capabilities are present. + */ + bool VerifyCaps(); +}; + +} /* namespace layers */ +} /* namespace mozilla */ + +#endif /* GFX_DEVICEMANAGERD3D9_H */ diff --git a/gfx/layers/d3d9/ImageLayerD3D9.cpp b/gfx/layers/d3d9/ImageLayerD3D9.cpp index d4fba66d40e..1bb1de06e16 100644 --- a/gfx/layers/d3d9/ImageLayerD3D9.cpp +++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp @@ -185,7 +185,7 @@ ImageLayerD3D9::RenderLayer() opacity[0] = GetOpacity(); device()->SetPixelShaderConstantF(0, opacity, 1); - mD3DManager->SetShaderMode(LayerManagerD3D9::YCBCRLAYER); + mD3DManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER); device()->SetTexture(0, yuvImage->mYTexture); device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); @@ -227,7 +227,7 @@ ImageLayerD3D9::RenderLayer() opacity[0] = GetOpacity(); device()->SetPixelShaderConstantF(0, opacity, 1); - mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER); + mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER); device()->SetTexture(0, cairoImage->mTexture); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); diff --git a/gfx/layers/d3d9/LayerManagerD3D9.cpp b/gfx/layers/d3d9/LayerManagerD3D9.cpp index 7ac7ecdc0dc..13a5d56bca6 100644 --- a/gfx/layers/d3d9/LayerManagerD3D9.cpp +++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp @@ -43,25 +43,10 @@ #include "ColorLayerD3D9.h" #include "CanvasLayerD3D9.h" -#include "LayerManagerD3D9Shaders.h" - -#include "nsIServiceManager.h" -#include "nsIConsoleService.h" -#include "nsPrintfCString.h" - namespace mozilla { namespace layers { -struct vertex { - float x, y; -}; - -IDirect3D9 *LayerManagerD3D9::mD3D9 = NULL; - -typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)( - UINT SDKVersion -); - +DeviceManagerD3D9 *LayerManagerD3D9::mDeviceManager = nsnull; LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget) { @@ -72,145 +57,39 @@ LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget) LayerManagerD3D9::~LayerManagerD3D9() { -} + /* Important to release this first since it also holds a reference to the + * device manager + */ + mSwapChain = nsnull; -#define HAS_CAP(a, b) (((a) & (b)) == (b)) -#define LACKS_CAP(a, b) !(((a) & (b)) == (b)) + if (mDeviceManager) { + if (!mDeviceManager->Release()) { + mDeviceManager = nsnull; + } + } +} PRBool LayerManagerD3D9::Initialize() { - if (!mD3D9) { - Direct3DCreate9Func d3d9create = (Direct3DCreate9Func) - GetProcAddress(LoadLibraryW(L"d3d9.dll"), "Direct3DCreate9"); - if (!d3d9create) { - return PR_FALSE; - } + if (!mDeviceManager) { + mDeviceManager = new DeviceManagerD3D9; - mD3D9 = d3d9create(D3D_SDK_VERSION); - if (!mD3D9) { + if (!mDeviceManager->Init()) { + mDeviceManager = nsnull; return PR_FALSE; } } - D3DPRESENT_PARAMETERS pp; - memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); + mDeviceManager->AddRef(); - pp.BackBufferFormat = D3DFMT_A8R8G8B8; - pp.SwapEffect = D3DSWAPEFFECT_COPY; - pp.Windowed = TRUE; - pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - pp.hDeviceWindow = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW); + mSwapChain = mDeviceManager-> + CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW)); - HRESULT hr = mD3D9->CreateDevice(D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, - NULL, - D3DCREATE_FPU_PRESERVE | - D3DCREATE_MULTITHREADED | - D3DCREATE_MIXED_VERTEXPROCESSING, - &pp, - getter_AddRefs(mDevice)); - - if (FAILED(hr)) { + if (!mSwapChain) { return PR_FALSE; } - if (!VerifyCaps()) { - return PR_FALSE; - } - - hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS, - getter_AddRefs(mLayerVS)); - - if (FAILED(hr)) { - return PR_FALSE; - } - - hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPS, - getter_AddRefs(mRGBPS)); - - if (FAILED(hr)) { - return PR_FALSE; - } - - hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPS, - getter_AddRefs(mYCbCrPS)); - - if (FAILED(hr)) { - return PR_FALSE; - } - - hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPS, - getter_AddRefs(mSolidColorPS)); - - if (FAILED(hr)) { - return PR_FALSE; - } - - hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4, - 0, - 0, - D3DPOOL_MANAGED, - getter_AddRefs(mVB), - NULL); - - if (FAILED(hr)) { - return PR_FALSE; - } - - vertex *vertices; - hr = mVB->Lock(0, 0, (void**)&vertices, 0); - if (FAILED(hr)) { - return PR_FALSE; - } - - vertices[0].x = vertices[0].y = 0; - vertices[1].x = 1; vertices[1].y = 0; - vertices[2].x = 0; vertices[2].y = 1; - vertices[3].x = 1; vertices[3].y = 1; - - mVB->Unlock(); - - hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex)); - if (FAILED(hr)) { - return PR_FALSE; - } - - D3DVERTEXELEMENT9 elements[] = { - { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, - D3DDECLUSAGE_POSITION, 0 }, - D3DDECL_END() - }; - - mDevice->CreateVertexDeclaration(elements, getter_AddRefs(mVD)); - - SetupRenderState(); - - nsCOMPtr - console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); - - D3DADAPTER_IDENTIFIER9 identifier; - mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier); - - if (console) { - nsString msg; - msg += - NS_LITERAL_STRING("Direct3D 9 LayerManager Initialized Succesfully.\nDriver: "); - msg += NS_ConvertUTF8toUTF16( - nsDependentCString((const char*)identifier.Driver)); - msg += NS_LITERAL_STRING("\nDescription: "); - msg += NS_ConvertUTF8toUTF16( - nsDependentCString((const char*)identifier.Description)); - msg += NS_LITERAL_STRING("\nVersion: "); - msg += NS_ConvertUTF8toUTF16( - nsPrintfCString("%d.%d.%d.%d", - HIWORD(identifier.DriverVersion.HighPart), - LOWORD(identifier.DriverVersion.HighPart), - HIWORD(identifier.DriverVersion.LowPart), - LOWORD(identifier.DriverVersion.LowPart))); - console->LogStringMessage(msg.get()); - } - return PR_TRUE; } @@ -298,38 +177,21 @@ LayerManagerD3D9::CreateImageContainer() return container.forget(); } -void -LayerManagerD3D9::SetShaderMode(ShaderMode aMode) -{ - switch (aMode) { - case RGBLAYER: - mDevice->SetVertexShader(mLayerVS); - mDevice->SetPixelShader(mRGBPS); - break; - case YCBCRLAYER: - mDevice->SetVertexShader(mLayerVS); - mDevice->SetPixelShader(mYCbCrPS); - break; - case SOLIDCOLORLAYER: - mDevice->SetVertexShader(mLayerVS); - mDevice->SetPixelShader(mSolidColorPS); - break; - } -} - void LayerManagerD3D9::Render() { - if (!SetupBackBuffer()) { + if (!mSwapChain->PrepareForRendering()) { return; } + deviceManager()->SetupRenderState(); + SetupPipeline(); nsIntRect rect; mWidget->GetClientBounds(rect); - mDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0); + device()->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0); - mDevice->BeginScene(); + device()->BeginScene(); if (mRootLayer) { const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect(); @@ -344,24 +206,18 @@ LayerManagerD3D9::Render() r.right = rect.width; r.bottom = rect.height; } - mDevice->SetScissorRect(&r); + device()->SetScissorRect(&r); mRootLayer->RenderLayer(); } - mDevice->EndScene(); + device()->EndScene(); if (!mTarget) { const nsIntRect *r; for (nsIntRegionRectIterator iter(mClippingRegion); (r = iter.Next()) != nsnull;) { - RECT rect; - rect.left = r->x; - rect.top = r->y; - rect.right = r->XMost(); - rect.bottom = r->YMost(); - - mDevice->Present(&rect, &rect, NULL, NULL); + mSwapChain->Present(*r); } } else { PaintToTarget(); @@ -387,86 +243,29 @@ LayerManagerD3D9::SetupPipeline() viewMatrix[3][1] = 1.0f; viewMatrix[3][3] = 1.0f; - HRESULT hr = mDevice->SetVertexShaderConstantF(8, &viewMatrix[0][0], 4); + HRESULT hr = device()->SetVertexShaderConstantF(8, &viewMatrix[0][0], 4); if (FAILED(hr)) { NS_WARNING("Failed to set projection shader constant!"); } } -PRBool -LayerManagerD3D9::SetupBackBuffer() -{ - nsRefPtr backBuffer; - mDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, - getter_AddRefs(backBuffer)); - - D3DSURFACE_DESC desc; - nsIntRect rect; - mWidget->GetClientBounds(rect); - backBuffer->GetDesc(&desc); - - HRESULT hr = mDevice->TestCooperativeLevel(); - - /* The device is lost or something else is wrong, failure */ - if (FAILED(hr) && hr != D3DERR_DEVICENOTRESET) { - return PR_FALSE; - } - - /* - * If the backbuffer is the right size, and the device is not lost, we can - * safely render without doing anything. - */ - if ((desc.Width == rect.width && desc.Height == rect.height) && - SUCCEEDED(hr)) { - return PR_TRUE; - } - - /* - * Our device is lost or our backbuffer needs resizing, start by clearing - * out all D3DPOOL_DEFAULT surfaces. - */ - for(unsigned int i = 0; i < mThebesLayers.Length(); i++) { - mThebesLayers[i]->CleanResources(); - } - - backBuffer = NULL; - - D3DPRESENT_PARAMETERS pp; - memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); - - pp.BackBufferFormat = D3DFMT_A8R8G8B8; - pp.SwapEffect = D3DSWAPEFFECT_COPY; - pp.Windowed = TRUE; - pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - pp.hDeviceWindow = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW); - - hr = mDevice->Reset(&pp); - if (FAILED(hr)) { - return PR_FALSE; - } - - SetupRenderState(); - - return PR_TRUE; -} - void LayerManagerD3D9::PaintToTarget() { nsRefPtr backBuff; nsRefPtr destSurf; - mDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, + device()->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, getter_AddRefs(backBuff)); D3DSURFACE_DESC desc; backBuff->GetDesc(&desc); - mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, + device()->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, getter_AddRefs(destSurf), NULL); - mDevice->GetRenderTargetData(backBuff, destSurf); + device()->GetRenderTargetData(backBuff, destSurf); D3DLOCKED_RECT rect; destSurf->LockRect(&rect, NULL, D3DLOCK_READONLY); @@ -483,81 +282,6 @@ LayerManagerD3D9::PaintToTarget() destSurf->UnlockRect(); } -void -LayerManagerD3D9::SetupRenderState() -{ - mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex)); - mDevice->SetVertexDeclaration(mVD); - mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); - mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); - mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); - mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - mDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - mDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - mDevice->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - mDevice->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); -} - -PRBool -LayerManagerD3D9::VerifyCaps() -{ - D3DCAPS9 caps; - HRESULT hr = mDevice->GetDeviceCaps(&caps); - - if (FAILED(hr)) { - return PR_FALSE; - } - - if (LACKS_CAP(caps.DevCaps, D3DDEVCAPS_TEXTUREVIDEOMEMORY)) { - return PR_FALSE; - } - - if (LACKS_CAP(caps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE)) { - return PR_FALSE; - } - - if (LACKS_CAP(caps.SrcBlendCaps, D3DPBLENDCAPS_ONE) || - LACKS_CAP(caps.SrcBlendCaps, D3DBLEND_SRCALPHA) || - LACKS_CAP(caps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA)) { - return PR_FALSE; - } - - if (LACKS_CAP(caps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST)) { - return PR_FALSE; - } - - if (LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_ALPHA) || - HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_SQUAREONLY) || - (HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_POW2) && - LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL))) { - return PR_FALSE; - } - - if (LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MAGFLINEAR) || - LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MINFLINEAR)) { - return PR_FALSE; - } - - if (LACKS_CAP(caps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP)) { - return PR_FALSE; - } - - if (caps.MaxTextureHeight < 4096 || - caps.MaxTextureWidth < 4096) { - return PR_FALSE; - } - - if ((caps.PixelShaderVersion & 0xffff) < 0x200 || - (caps.VertexShaderVersion & 0xffff) < 0x200) { - return PR_FALSE; - } - return PR_TRUE; -} - LayerD3D9::LayerD3D9(LayerManagerD3D9 *aManager) : mD3DManager(aManager) { diff --git a/gfx/layers/d3d9/LayerManagerD3D9.h b/gfx/layers/d3d9/LayerManagerD3D9.h index b17c9a4a125..56f7bcaad45 100644 --- a/gfx/layers/d3d9/LayerManagerD3D9.h +++ b/gfx/layers/d3d9/LayerManagerD3D9.h @@ -46,6 +46,8 @@ #include "gfxContext.h" #include "nsIWidget.h" +#include "DeviceManagerD3D9.h" + namespace mozilla { namespace layers { @@ -122,49 +124,27 @@ public: */ void SetClippingEnabled(PRBool aEnabled); - IDirect3DDevice9 *device() const { return mDevice; } + void SetShaderMode(DeviceManagerD3D9::ShaderMode aMode) + { mDeviceManager->SetShaderMode(aMode); } - enum ShaderMode { - RGBLAYER, - YCBCRLAYER, - SOLIDCOLORLAYER - }; - - void SetShaderMode(ShaderMode aMode); - - nsTArray mThebesLayers; + IDirect3DDevice9 *device() const { return mDeviceManager->device(); } + DeviceManagerD3D9 *deviceManager() const { return mDeviceManager; } private: - /* Direct3D9 instance */ - static IDirect3D9 *mD3D9; + /* Device manager instance */ + static DeviceManagerD3D9 *mDeviceManager; + + /* Swap chain associated with this layer manager */ + nsRefPtr mSwapChain; /* Widget associated with this layer manager */ nsIWidget *mWidget; + /* * Context target, NULL when drawing directly to our swap chain. */ nsRefPtr mTarget; - nsRefPtr mDevice; - - /* Vertex shader used for layer quads */ - nsRefPtr mLayerVS; - - /* Pixel shader used for RGB textures */ - nsRefPtr mRGBPS; - - /* Pixel shader used for RGB textures */ - nsRefPtr mYCbCrPS; - - /* Pixel shader used for solid colors */ - nsRefPtr mSolidColorPS; - - /* Vertex buffer containing our basic vertex structure */ - nsRefPtr mVB; - - /* Our vertex declaration */ - nsRefPtr mVD; - /* Current root layer. */ LayerD3D9 *mRootLayer; @@ -175,32 +155,21 @@ private: * Region we're clipping our current drawing to. */ nsIntRegion mClippingRegion; + /* * Render the current layer tree to the active target. */ void Render(); + /* * Setup the pipeline. */ void SetupPipeline(); - /* - * Setup the backbuffer. - * - * \return PR_TRUE if setup was succesful - */ - PRBool SetupBackBuffer(); - /* - * Setup the render state for the surface. - */ - void SetupRenderState(); + /* * Copies the content of our backbuffer to the set transaction target. */ void PaintToTarget(); - /* - * Verifies all required device capabilities are present. - */ - PRBool VerifyCaps(); }; diff --git a/gfx/layers/d3d9/ThebesLayerD3D9.cpp b/gfx/layers/d3d9/ThebesLayerD3D9.cpp index ac659e43128..b8c0c356785 100644 --- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp +++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp @@ -69,12 +69,12 @@ ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager) , LayerD3D9(aManager) { mImplData = static_cast(this); - aManager->mThebesLayers.AppendElement(this); + aManager->deviceManager()->mThebesLayers.AppendElement(this); } ThebesLayerD3D9::~ThebesLayerD3D9() { - mD3DManager->mThebesLayers.RemoveElement(this); + mD3DManager->deviceManager()->mThebesLayers.RemoveElement(this); } /** @@ -338,7 +338,7 @@ ThebesLayerD3D9::RenderLayer() opacity[0] = GetOpacity(); device()->SetPixelShaderConstantF(0, opacity, 1); - mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER); + mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER); device()->SetTexture(0, mTexture); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);