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 michael@0: michael@0: #include "LayerManagerD3D10.h" michael@0: #include "LayerManagerD3D10Effect.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "gfx2DGlue.h" michael@0: #include "gfxD2DSurface.h" michael@0: #include "gfxFailure.h" michael@0: #include "cairo-win32.h" michael@0: #include "dxgi.h" michael@0: michael@0: #include "ContainerLayerD3D10.h" michael@0: #include "ThebesLayerD3D10.h" michael@0: #include "ColorLayerD3D10.h" michael@0: #include "CanvasLayerD3D10.h" michael@0: #include "ReadbackLayerD3D10.h" michael@0: #include "ImageLayerD3D10.h" michael@0: #include "mozilla/layers/PLayerChild.h" michael@0: #include "mozilla/WidgetUtils.h" michael@0: michael@0: #include "../d3d9/Nv3DVUtils.h" michael@0: michael@0: #include "gfxCrashReporterUtils.h" michael@0: #include "nsWindowsHelpers.h" michael@0: #ifdef MOZ_METRO michael@0: #include "DXGI1_2.h" michael@0: #endif michael@0: michael@0: using namespace std; michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: struct Vertex michael@0: { michael@0: float position[2]; michael@0: }; michael@0: michael@0: // {592BF306-0EED-4F76-9D03-A0846450F472} michael@0: static const GUID sDeviceAttachments = michael@0: { 0x592bf306, 0xeed, 0x4f76, { 0x9d, 0x3, 0xa0, 0x84, 0x64, 0x50, 0xf4, 0x72 } }; michael@0: // {716AEDB1-C9C3-4B4D-8332-6F65D44AF6A8} michael@0: static const GUID sLayerManagerCount = michael@0: { 0x716aedb1, 0xc9c3, 0x4b4d, { 0x83, 0x32, 0x6f, 0x65, 0xd4, 0x4a, 0xf6, 0xa8 } }; michael@0: michael@0: LayerManagerD3D10::LayerManagerD3D10(nsIWidget *aWidget) michael@0: : mWidget(aWidget) michael@0: , mDisableSequenceForNextFrame(false) michael@0: { michael@0: } michael@0: michael@0: struct DeviceAttachments michael@0: { michael@0: nsRefPtr mEffect; michael@0: nsRefPtr mInputLayout; michael@0: nsRefPtr mVertexBuffer; michael@0: nsRefPtr mReadbackManager; michael@0: }; michael@0: michael@0: LayerManagerD3D10::~LayerManagerD3D10() 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, sizeof(referenceCount), &referenceCount); michael@0: michael@0: if (!referenceCount) { michael@0: DeviceAttachments *attachments; michael@0: size = sizeof(attachments); michael@0: mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments); michael@0: // No LayerManagers left for this device. Clear out interfaces stored which michael@0: // hold a reference to the device. michael@0: mDevice->SetPrivateData(sDeviceAttachments, 0, nullptr); michael@0: michael@0: delete attachments; michael@0: } michael@0: } michael@0: michael@0: Destroy(); michael@0: } michael@0: michael@0: static inline void michael@0: SetHRESULT(HRESULT* aHresultPtr, HRESULT aHresult) michael@0: { michael@0: if (aHresultPtr) { michael@0: *aHresultPtr = aHresult; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: LayerManagerD3D10::Initialize(bool force, HRESULT* aHresultPtr) michael@0: { michael@0: ScopedGfxFeatureReporter reporter("D3D10 Layers", force); michael@0: michael@0: HRESULT hr = E_UNEXPECTED; michael@0: michael@0: /* Create an Nv3DVUtils instance */ michael@0: if (!mNv3DVUtils) { michael@0: mNv3DVUtils = new Nv3DVUtils(); michael@0: if (!mNv3DVUtils) { michael@0: NS_WARNING("Could not create a new instance of Nv3DVUtils.\n"); michael@0: } michael@0: } michael@0: michael@0: /* Initialize the Nv3DVUtils object */ michael@0: if (mNv3DVUtils) { michael@0: mNv3DVUtils->Initialize(); michael@0: } michael@0: michael@0: mDevice = gfxWindowsPlatform::GetPlatform()->GetD3D10Device(); michael@0: if (!mDevice) { michael@0: SetHRESULT(aHresultPtr, hr); michael@0: return false; michael@0: } michael@0: michael@0: /* michael@0: * Do some post device creation setup michael@0: */ michael@0: if (mNv3DVUtils) { michael@0: IUnknown* devUnknown = nullptr; michael@0: if (mDevice) { michael@0: mDevice->QueryInterface(IID_IUnknown, (void **)&devUnknown); michael@0: } michael@0: mNv3DVUtils->SetDeviceInfo(devUnknown); michael@0: } 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, sizeof(referenceCount), &referenceCount); michael@0: michael@0: DeviceAttachments *attachments; michael@0: size = sizeof(DeviceAttachments*); michael@0: if (FAILED(mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments))) { michael@0: attachments = new DeviceAttachments; michael@0: mDevice->SetPrivateData(sDeviceAttachments, sizeof(attachments), &attachments); michael@0: michael@0: SetLastError(0); michael@0: decltype(D3D10CreateEffectFromMemory)* createEffect = michael@0: (decltype(D3D10CreateEffectFromMemory)*) michael@0: GetProcAddress(LoadLibraryA("d3d10_1.dll"), "D3D10CreateEffectFromMemory"); michael@0: if (!createEffect) { michael@0: SetHRESULT(aHresultPtr, HRESULT_FROM_WIN32(GetLastError())); michael@0: return false; michael@0: } michael@0: michael@0: hr = createEffect((void*)g_main, michael@0: sizeof(g_main), michael@0: D3D10_EFFECT_SINGLE_THREADED, michael@0: mDevice, michael@0: nullptr, michael@0: getter_AddRefs(mEffect)); michael@0: michael@0: if (FAILED(hr)) { michael@0: SetHRESULT(aHresultPtr, hr); michael@0: return false; michael@0: } michael@0: michael@0: attachments->mEffect = mEffect; michael@0: michael@0: D3D10_INPUT_ELEMENT_DESC layout[] = michael@0: { michael@0: { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, michael@0: }; michael@0: D3D10_PASS_DESC passDesc; michael@0: mEffect->GetTechniqueByName("RenderRGBLayerPremul")->GetPassByIndex(0)-> michael@0: GetDesc(&passDesc); michael@0: michael@0: hr = mDevice->CreateInputLayout(layout, michael@0: sizeof(layout) / sizeof(D3D10_INPUT_ELEMENT_DESC), michael@0: passDesc.pIAInputSignature, michael@0: passDesc.IAInputSignatureSize, michael@0: getter_AddRefs(mInputLayout)); michael@0: michael@0: if (FAILED(hr)) { michael@0: SetHRESULT(aHresultPtr, hr); michael@0: return false; michael@0: } michael@0: michael@0: attachments->mInputLayout = mInputLayout; michael@0: michael@0: Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} }; michael@0: CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER); michael@0: D3D10_SUBRESOURCE_DATA data; michael@0: data.pSysMem = (void*)vertices; michael@0: michael@0: hr = mDevice->CreateBuffer(&bufferDesc, &data, getter_AddRefs(mVertexBuffer)); michael@0: michael@0: if (FAILED(hr)) { michael@0: SetHRESULT(aHresultPtr, hr); michael@0: return false; michael@0: } michael@0: michael@0: attachments->mVertexBuffer = mVertexBuffer; michael@0: } else { michael@0: mEffect = attachments->mEffect; michael@0: mVertexBuffer = attachments->mVertexBuffer; michael@0: mInputLayout = attachments->mInputLayout; 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: SetHRESULT(aHresultPtr, 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 = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW); 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, getter_AddRefs(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, DXGI_MWA_NO_WINDOW_CHANGES); michael@0: } michael@0: michael@0: reporter.SetSuccessful(); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::Destroy() michael@0: { michael@0: if (!IsDestroyed()) { michael@0: if (mRoot) { michael@0: static_cast(mRoot->ImplData())->LayerManagerDestroyed(); michael@0: } michael@0: // XXX need to be careful here about surface destruction michael@0: // racing with share-to-chrome message michael@0: } michael@0: LayerManager::Destroy(); michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::SetRoot(Layer *aRoot) michael@0: { michael@0: mRoot = aRoot; michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::BeginTransaction() michael@0: { michael@0: mInTransaction = true; michael@0: michael@0: #ifdef MOZ_LAYERS_HAVE_LOG michael@0: MOZ_LAYERS_LOG(("[----- BeginTransaction")); michael@0: Log(); michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::BeginTransactionWithTarget(gfxContext* aTarget) michael@0: { michael@0: mInTransaction = true; michael@0: mTarget = aTarget; michael@0: } michael@0: michael@0: bool michael@0: LayerManagerD3D10::EndEmptyTransaction(EndTransactionFlags aFlags) michael@0: { michael@0: mInTransaction = false; michael@0: michael@0: if (!mRoot) michael@0: return false; michael@0: michael@0: EndTransaction(nullptr, nullptr, aFlags); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::EndTransaction(DrawThebesLayerCallback aCallback, michael@0: void* aCallbackData, michael@0: EndTransactionFlags aFlags) michael@0: { michael@0: mInTransaction = false; michael@0: michael@0: if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) { michael@0: mCurrentCallbackInfo.Callback = aCallback; michael@0: mCurrentCallbackInfo.CallbackData = aCallbackData; michael@0: michael@0: if (aFlags & END_NO_COMPOSITE) { michael@0: // Apply pending tree updates before recomputing effective michael@0: // properties. michael@0: mRoot->ApplyPendingUpdatesToSubtree(); michael@0: } michael@0: michael@0: // The results of our drawing always go directly into a pixel buffer, michael@0: // so we don't need to pass any global transform here. michael@0: mRoot->ComputeEffectiveTransforms(Matrix4x4()); michael@0: michael@0: #ifdef MOZ_LAYERS_HAVE_LOG michael@0: MOZ_LAYERS_LOG((" ----- (beginning paint)")); michael@0: Log(); michael@0: #endif michael@0: michael@0: Render(aFlags); michael@0: mCurrentCallbackInfo.Callback = nullptr; michael@0: mCurrentCallbackInfo.CallbackData = nullptr; michael@0: } michael@0: michael@0: #ifdef MOZ_LAYERS_HAVE_LOG michael@0: Log(); michael@0: MOZ_LAYERS_LOG(("]----- EndTransaction")); michael@0: #endif michael@0: michael@0: mTarget = nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: LayerManagerD3D10::CreateThebesLayer() michael@0: { michael@0: nsRefPtr layer = new ThebesLayerD3D10(this); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: LayerManagerD3D10::CreateContainerLayer() michael@0: { michael@0: nsRefPtr layer = new ContainerLayerD3D10(this); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: LayerManagerD3D10::CreateImageLayer() michael@0: { michael@0: nsRefPtr layer = new ImageLayerD3D10(this); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: LayerManagerD3D10::CreateColorLayer() michael@0: { michael@0: nsRefPtr layer = new ColorLayerD3D10(this); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: LayerManagerD3D10::CreateCanvasLayer() michael@0: { michael@0: nsRefPtr layer = new CanvasLayerD3D10(this); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: LayerManagerD3D10::CreateReadbackLayer() michael@0: { michael@0: nsRefPtr layer = new ReadbackLayerD3D10(this); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: static void ReleaseTexture(void *texture) michael@0: { michael@0: static_cast(texture)->Release(); michael@0: } michael@0: michael@0: TemporaryRef michael@0: LayerManagerD3D10::CreateOptimalDrawTarget(const IntSize &aSize, michael@0: SurfaceFormat aFormat) michael@0: { michael@0: if ((aFormat != SurfaceFormat::B8G8R8X8 && michael@0: aFormat != SurfaceFormat::B8G8R8A8)) { michael@0: return LayerManager::CreateOptimalDrawTarget(aSize, aFormat); michael@0: } michael@0: michael@0: nsRefPtr texture; michael@0: michael@0: CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1); michael@0: desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; michael@0: desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE; michael@0: michael@0: HRESULT hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture)); michael@0: michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to create new texture for CreateOptimalDrawTarget!"); michael@0: return LayerManager::CreateOptimalDrawTarget(aSize, aFormat); michael@0: } michael@0: michael@0: RefPtr dt = michael@0: Factory::CreateDrawTargetForD3D10Texture(texture, aFormat); michael@0: michael@0: if (!dt) { michael@0: return LayerManager::CreateOptimalDrawTarget(aSize, aFormat); michael@0: } michael@0: michael@0: return dt; michael@0: } michael@0: michael@0: michael@0: TemporaryRef michael@0: LayerManagerD3D10::CreateOptimalMaskDrawTarget(const IntSize &aSize) michael@0: { michael@0: return CreateOptimalDrawTarget(aSize, SurfaceFormat::B8G8R8A8); michael@0: } michael@0: michael@0: michael@0: TemporaryRef michael@0: LayerManagerD3D10::CreateDrawTarget(const IntSize &aSize, michael@0: SurfaceFormat aFormat) michael@0: { michael@0: if ((aFormat != SurfaceFormat::B8G8R8A8 && michael@0: aFormat != SurfaceFormat::B8G8R8X8) || michael@0: gfxPlatform::GetPlatform()->GetPreferredCanvasBackend() != BackendType::DIRECT2D) { michael@0: return LayerManager::CreateDrawTarget(aSize, aFormat); michael@0: } michael@0: michael@0: nsRefPtr texture; michael@0: michael@0: CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1); michael@0: desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; michael@0: michael@0: HRESULT hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture)); michael@0: michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to create new texture for CreateOptimalDrawTarget!"); michael@0: return LayerManager::CreateDrawTarget(aSize, aFormat); michael@0: } michael@0: michael@0: RefPtr surface = michael@0: Factory::CreateDrawTargetForD3D10Texture(texture, aFormat); michael@0: michael@0: if (!surface) { michael@0: return LayerManager::CreateDrawTarget(aSize, aFormat); michael@0: } michael@0: michael@0: return surface; michael@0: } michael@0: michael@0: ReadbackManagerD3D10* michael@0: LayerManagerD3D10::readbackManager() michael@0: { michael@0: EnsureReadbackManager(); michael@0: return mReadbackManager; michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::SetViewport(const nsIntSize &aViewport) michael@0: { michael@0: mViewport = aViewport; michael@0: michael@0: D3D10_VIEWPORT viewport; michael@0: viewport.MaxDepth = 1.0f; michael@0: viewport.MinDepth = 0; michael@0: viewport.Width = aViewport.width; michael@0: viewport.Height = aViewport.height; michael@0: viewport.TopLeftX = 0; michael@0: viewport.TopLeftY = 0; michael@0: michael@0: mDevice->RSSetViewports(1, &viewport); michael@0: michael@0: gfx3DMatrix projection; 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: projection._11 = 2.0f / aViewport.width; michael@0: projection._22 = -2.0f / aViewport.height; michael@0: projection._33 = 0.0f; michael@0: projection._41 = -1.0f; michael@0: projection._42 = 1.0f; michael@0: projection._44 = 1.0f; michael@0: michael@0: HRESULT hr = mEffect->GetVariableByName("mProjection")-> michael@0: SetRawValue(&projection._11, 0, 64); 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: LayerManagerD3D10::SetupInputAssembler() michael@0: { michael@0: mDevice->IASetInputLayout(mInputLayout); michael@0: michael@0: UINT stride = sizeof(Vertex); michael@0: UINT offset = 0; michael@0: ID3D10Buffer *buffer = mVertexBuffer; michael@0: mDevice->IASetVertexBuffers(0, 1, &buffer, &stride, &offset); michael@0: mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::SetupPipeline() michael@0: { michael@0: VerifyBufferSize(); michael@0: UpdateRenderTarget(); michael@0: michael@0: nsIntRect rect; michael@0: mWidget->GetClientBounds(rect); michael@0: michael@0: HRESULT hr; michael@0: michael@0: hr = mEffect->GetVariableByName("vTextureCoords")->AsVector()-> michael@0: SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f)); michael@0: michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to set Texture Coordinates."); michael@0: return; michael@0: } michael@0: michael@0: ID3D10RenderTargetView *view = mRTView; michael@0: mDevice->OMSetRenderTargets(1, &view, nullptr); michael@0: michael@0: SetupInputAssembler(); michael@0: michael@0: SetViewport(nsIntSize(rect.width, rect.height)); michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::UpdateRenderTarget() michael@0: { michael@0: if (mRTView || !mSwapChain) { michael@0: return; michael@0: } michael@0: michael@0: HRESULT hr; michael@0: michael@0: nsRefPtr backBuf; michael@0: hr = mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)backBuf.StartAssignment()); michael@0: if (FAILED(hr)) { michael@0: return; michael@0: } michael@0: mDevice->CreateRenderTargetView(backBuf, nullptr, getter_AddRefs(mRTView)); michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::VerifyBufferSize() michael@0: { michael@0: nsIntRect rect; michael@0: mWidget->GetClientBounds(rect); michael@0: michael@0: if (mSwapChain) { michael@0: DXGI_SWAP_CHAIN_DESC swapDesc; michael@0: mSwapChain->GetDesc(&swapDesc); michael@0: michael@0: if (swapDesc.BufferDesc.Width == rect.width && michael@0: swapDesc.BufferDesc.Height == rect.height) { michael@0: return; michael@0: } michael@0: michael@0: mRTView = nullptr; michael@0: if (IsRunningInWindowsMetro()) { michael@0: mSwapChain->ResizeBuffers(2, rect.width, rect.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, rect.width, rect.height, michael@0: DXGI_FORMAT_B8G8R8A8_UNORM, michael@0: 0); michael@0: } else { michael@0: mSwapChain->ResizeBuffers(1, rect.width, rect.height, michael@0: DXGI_FORMAT_B8G8R8A8_UNORM, michael@0: DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::EnsureReadbackManager() michael@0: { michael@0: if (mReadbackManager) { michael@0: return; michael@0: } michael@0: michael@0: DeviceAttachments *attachments; michael@0: UINT size = sizeof(DeviceAttachments*); michael@0: if (FAILED(mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments))) { michael@0: // Strange! This shouldn't happen ... return a readback manager for this michael@0: // layer manager only. michael@0: mReadbackManager = new ReadbackManagerD3D10(); michael@0: gfx::LogFailure(NS_LITERAL_CSTRING("Couldn't get device attachments for device.")); michael@0: return; michael@0: } michael@0: michael@0: if (attachments->mReadbackManager) { michael@0: mReadbackManager = attachments->mReadbackManager; michael@0: return; michael@0: } michael@0: michael@0: mReadbackManager = new ReadbackManagerD3D10(); michael@0: attachments->mReadbackManager = mReadbackManager; michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::Render(EndTransactionFlags aFlags) michael@0: { michael@0: static_cast(mRoot->ImplData())->Validate(); michael@0: michael@0: if (aFlags & END_NO_COMPOSITE) { michael@0: return; michael@0: } michael@0: michael@0: SetupPipeline(); michael@0: michael@0: float black[] = { 0, 0, 0, 0 }; michael@0: device()->ClearRenderTargetView(mRTView, black); michael@0: michael@0: nsIntRect rect; michael@0: mWidget->GetClientBounds(rect); michael@0: michael@0: const nsIntRect *clipRect = mRoot->GetClipRect(); michael@0: D3D10_RECT r; michael@0: if (clipRect) { michael@0: r.left = (LONG)clipRect->x; michael@0: r.top = (LONG)clipRect->y; michael@0: r.right = (LONG)(clipRect->x + clipRect->width); michael@0: r.bottom = (LONG)(clipRect->y + clipRect->height); michael@0: } else { michael@0: r.left = r.top = 0; michael@0: r.right = rect.width; michael@0: r.bottom = rect.height; michael@0: } michael@0: device()->RSSetScissorRects(1, &r); michael@0: michael@0: static_cast(mRoot->ImplData())->RenderLayer(); michael@0: michael@0: if (!mRegionToClear.IsEmpty()) { michael@0: float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; michael@0: gfx::Matrix4x4 transform; michael@0: effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform, 0, 64); michael@0: effect()->GetVariableByName("fLayerColor")->AsVector()->SetFloatVector(color); michael@0: michael@0: ID3D10EffectTechnique *technique = effect()->GetTechniqueByName("RenderClearLayer"); michael@0: michael@0: nsIntRegionRectIterator iter(mRegionToClear); michael@0: const nsIntRect *r; michael@0: while ((r = iter.Next())) { michael@0: effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( michael@0: ShaderConstantRectD3D10( michael@0: (float)r->x, michael@0: (float)r->y, michael@0: (float)r->width, michael@0: (float)r->height) michael@0: ); michael@0: michael@0: technique->GetPassByIndex(0)->Apply(0); michael@0: device()->Draw(4, 0); michael@0: } michael@0: } michael@0: michael@0: // See bug 630197 - we have some reasons to believe if an earlier call michael@0: // returned an error, the upcoming present call may raise an exception. michael@0: // This will check if any of the calls done recently has returned an error michael@0: // and bails on composition. On the -next- frame we will then abandon michael@0: // hardware acceleration from gfxWindowsPlatform::VerifyD2DDevice. michael@0: // This might not be the 'optimal' solution but it will help us assert michael@0: // whether our thoughts of the causes of the issues are correct. michael@0: if (FAILED(mDevice->GetDeviceRemovedReason())) { michael@0: return; michael@0: } michael@0: michael@0: if (mTarget) { michael@0: PaintToTarget(); michael@0: } else { michael@0: mSwapChain->Present(0, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0); michael@0: mDisableSequenceForNextFrame = false; michael@0: } michael@0: RecordFrame(); michael@0: PostPresent(); michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::PaintToTarget() michael@0: { michael@0: nsRefPtr backBuf; michael@0: michael@0: mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)backBuf.StartAssignment()); michael@0: michael@0: D3D10_TEXTURE2D_DESC bbDesc; michael@0: backBuf->GetDesc(&bbDesc); michael@0: michael@0: CD3D10_TEXTURE2D_DESC softDesc(bbDesc.Format, bbDesc.Width, bbDesc.Height); michael@0: softDesc.MipLevels = 1; michael@0: softDesc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; michael@0: softDesc.Usage = D3D10_USAGE_STAGING; michael@0: softDesc.BindFlags = 0; michael@0: michael@0: nsRefPtr readTexture; michael@0: michael@0: HRESULT hr = device()->CreateTexture2D(&softDesc, nullptr, getter_AddRefs(readTexture)); michael@0: if (FAILED(hr)) { michael@0: ReportFailure(NS_LITERAL_CSTRING("LayerManagerD3D10::PaintToTarget(): Failed to create texture"), michael@0: hr); michael@0: return; michael@0: } michael@0: michael@0: device()->CopyResource(readTexture, backBuf); michael@0: michael@0: D3D10_MAPPED_TEXTURE2D map; michael@0: readTexture->Map(0, D3D10_MAP_READ, 0, &map); michael@0: michael@0: nsRefPtr tmpSurface = michael@0: new gfxImageSurface((unsigned char*)map.pData, michael@0: gfxIntSize(bbDesc.Width, bbDesc.Height), michael@0: map.RowPitch, michael@0: gfxImageFormat::ARGB32); michael@0: michael@0: mTarget->SetSource(tmpSurface); michael@0: mTarget->SetOperator(gfxContext::OPERATOR_OVER); michael@0: mTarget->Paint(); michael@0: michael@0: readTexture->Unmap(0); michael@0: } michael@0: michael@0: void michael@0: LayerManagerD3D10::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: LayerD3D10::LayerD3D10(LayerManagerD3D10 *aManager) michael@0: : mD3DManager(aManager) michael@0: { michael@0: } michael@0: michael@0: ID3D10EffectTechnique* michael@0: LayerD3D10::SelectShader(uint8_t aFlags) michael@0: { michael@0: switch (aFlags) { michael@0: case (SHADER_RGBA | SHADER_NON_PREMUL | SHADER_LINEAR | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerNonPremulMask"); michael@0: case (SHADER_RGBA | SHADER_NON_PREMUL | SHADER_LINEAR | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerNonPremul"); michael@0: case (SHADER_RGBA | SHADER_NON_PREMUL | SHADER_POINT | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerNonPremulPoint"); michael@0: case (SHADER_RGBA | SHADER_NON_PREMUL | SHADER_POINT | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerNonPremulPointMask"); michael@0: case (SHADER_RGBA | SHADER_PREMUL | SHADER_LINEAR | SHADER_MASK_3D): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerPremulMask3D"); michael@0: case (SHADER_RGBA | SHADER_PREMUL | SHADER_LINEAR | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerPremulMask"); michael@0: case (SHADER_RGBA | SHADER_PREMUL | SHADER_LINEAR | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerPremul"); michael@0: case (SHADER_RGBA | SHADER_PREMUL | SHADER_POINT | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerPremulPointMask"); michael@0: case (SHADER_RGBA | SHADER_PREMUL | SHADER_POINT | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBALayerPremulPoint"); michael@0: case (SHADER_RGB | SHADER_PREMUL | SHADER_POINT | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBLayerPremulPointMask"); michael@0: case (SHADER_RGB | SHADER_PREMUL | SHADER_POINT | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBLayerPremulPoint"); michael@0: case (SHADER_RGB | SHADER_PREMUL | SHADER_LINEAR | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBLayerPremulMask"); michael@0: case (SHADER_RGB | SHADER_PREMUL | SHADER_LINEAR | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderRGBLayerPremul"); michael@0: case (SHADER_SOLID | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderSolidColorLayerMask"); michael@0: case (SHADER_SOLID | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderSolidColorLayer"); michael@0: case (SHADER_COMPONENT_ALPHA | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderComponentAlphaLayerMask"); michael@0: case (SHADER_COMPONENT_ALPHA | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderComponentAlphaLayer"); michael@0: case (SHADER_YCBCR | SHADER_MASK): michael@0: return effect()->GetTechniqueByName("RenderYCbCrLayerMask"); michael@0: case (SHADER_YCBCR | SHADER_NO_MASK): michael@0: return effect()->GetTechniqueByName("RenderYCbCrLayer"); michael@0: default: michael@0: NS_ERROR("Invalid shader."); michael@0: return nullptr; michael@0: } michael@0: } michael@0: michael@0: uint8_t michael@0: LayerD3D10::LoadMaskTexture() michael@0: { michael@0: if (Layer* maskLayer = GetLayer()->GetMaskLayer()) { michael@0: IntSize size; michael@0: nsRefPtr maskSRV = michael@0: static_cast(maskLayer->ImplData())->GetAsTexture(&size); michael@0: michael@0: if (!maskSRV) { michael@0: return SHADER_NO_MASK; michael@0: } michael@0: michael@0: Matrix maskTransform; michael@0: Matrix4x4 effectiveTransform = maskLayer->GetEffectiveTransform(); michael@0: bool maskIs2D = effectiveTransform.CanDraw2D(&maskTransform); michael@0: NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!"); michael@0: Rect bounds = Rect(Point(), Size(size)); michael@0: bounds = maskTransform.TransformBounds(bounds); michael@0: michael@0: effect()->GetVariableByName("vMaskQuad")->AsVector()->SetFloatVector( michael@0: ShaderConstantRectD3D10( michael@0: (float)bounds.x, michael@0: (float)bounds.y, michael@0: (float)bounds.width, michael@0: (float)bounds.height) michael@0: ); michael@0: michael@0: effect()->GetVariableByName("tMask")->AsShaderResource()->SetResource(maskSRV); michael@0: return SHADER_MASK; michael@0: } michael@0: michael@0: return SHADER_NO_MASK; michael@0: } michael@0: michael@0: } michael@0: }