summaryrefslogtreecommitdiffstats
path: root/gfx/layers/d3d11/MLGDeviceD3D11.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/layers/d3d11/MLGDeviceD3D11.cpp
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/d3d11/MLGDeviceD3D11.cpp')
-rw-r--r--gfx/layers/d3d11/MLGDeviceD3D11.cpp2034
1 files changed, 2034 insertions, 0 deletions
diff --git a/gfx/layers/d3d11/MLGDeviceD3D11.cpp b/gfx/layers/d3d11/MLGDeviceD3D11.cpp
new file mode 100644
index 0000000000..219662ead1
--- /dev/null
+++ b/gfx/layers/d3d11/MLGDeviceD3D11.cpp
@@ -0,0 +1,2034 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MLGDeviceD3D11.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/WindowsVersion.h"
+#include "mozilla/gfx/GPUParent.h"
+#include "mozilla/gfx/StackArray.h"
+#include "mozilla/layers/DiagnosticsD3D11.h"
+#include "mozilla/layers/HelpersD3D11.h"
+#include "mozilla/layers/LayerMLGPU.h"
+#include "mozilla/layers/MemoryReportingMLGPU.h"
+#include "mozilla/layers/ShaderDefinitionsMLGPU.h"
+#include "mozilla/layers/UtilityMLGPU.h"
+#include "mozilla/widget/CompositorWidget.h"
+#include "mozilla/widget/WinCompositorWidget.h"
+#include "MLGShaders.h"
+#include "TextureD3D11.h"
+#include "gfxConfig.h"
+#include "mozilla/StaticPrefs_layers.h"
+#include "FxROutputHandler.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+using namespace mozilla::widget;
+using namespace mozilla::layers::mlg;
+
+// Defined in CompositorD3D11.cpp.
+bool CanUsePartialPresents(ID3D11Device* aDevice);
+
+static D3D11_BOX RectToBox(const gfx::IntRect& aRect);
+
+MLGRenderTargetD3D11::MLGRenderTargetD3D11(const gfx::IntSize& aSize,
+ MLGRenderTargetFlags aFlags)
+ : MLGRenderTarget(aFlags), mSize(aSize) {}
+
+MLGRenderTargetD3D11::~MLGRenderTargetD3D11() {
+ if (mDepthBuffer) {
+ sRenderTargetUsage -= mSize.width * mSize.height * 1;
+ }
+ ForgetTexture();
+}
+
+bool MLGRenderTargetD3D11::Initialize(ID3D11Device* aDevice) {
+ D3D11_TEXTURE2D_DESC desc;
+ ::ZeroMemory(&desc, sizeof(desc));
+ desc.Width = mSize.width;
+ desc.Height = mSize.height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.SampleDesc.Count = 1;
+ desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
+
+ RefPtr<ID3D11Texture2D> texture;
+ HRESULT hr =
+ aDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
+ if (FAILED(hr) || !texture) {
+ gfxCriticalNote << "Failed to create render target texture: " << hexa(hr);
+ return false;
+ }
+
+ return Initialize(aDevice, texture);
+}
+
+bool MLGRenderTargetD3D11::Initialize(ID3D11Device* aDevice,
+ ID3D11Texture2D* aTexture) {
+ if (!UpdateTexture(aTexture)) {
+ return false;
+ }
+ if ((mFlags & MLGRenderTargetFlags::ZBuffer) && !CreateDepthBuffer(aDevice)) {
+ return false;
+ }
+ return true;
+}
+
+bool MLGRenderTargetD3D11::UpdateTexture(ID3D11Texture2D* aTexture) {
+ // Save the view first, in case we can re-use it.
+ RefPtr<ID3D11RenderTargetView> view = mRTView.forget();
+
+ ForgetTexture();
+
+ if (!aTexture) {
+ return true;
+ }
+
+#ifdef DEBUG
+ D3D11_TEXTURE2D_DESC desc;
+ aTexture->GetDesc(&desc);
+ MOZ_ASSERT(desc.Width == mSize.width && desc.Height == mSize.height);
+#endif
+
+ RefPtr<ID3D11Device> device;
+ aTexture->GetDevice(getter_AddRefs(device));
+
+ if (view) {
+ // Check that the view matches the backing texture.
+ RefPtr<ID3D11Resource> resource;
+ view->GetResource(getter_AddRefs(resource));
+ if (resource != aTexture) {
+ view = nullptr;
+ }
+ }
+
+ // If we couldn't re-use a view from before, make one now.
+ if (!view) {
+ HRESULT hr =
+ device->CreateRenderTargetView(aTexture, nullptr, getter_AddRefs(view));
+ if (FAILED(hr) || !view) {
+ gfxCriticalNote << "Failed to create render target view: " << hexa(hr);
+ return false;
+ }
+ }
+
+ mTexture = aTexture;
+ mRTView = view.forget();
+ sRenderTargetUsage += mSize.width * mSize.height * 4;
+ return true;
+}
+
+void MLGRenderTargetD3D11::ForgetTexture() {
+ if (mTexture) {
+ sRenderTargetUsage -= mSize.width * mSize.height * 4;
+ mTexture = nullptr;
+ }
+ mRTView = nullptr;
+ mTextureSource = nullptr;
+}
+
+bool MLGRenderTargetD3D11::CreateDepthBuffer(ID3D11Device* aDevice) {
+ D3D11_TEXTURE2D_DESC desc;
+ ::ZeroMemory(&desc, sizeof(desc));
+ desc.Width = mSize.width;
+ desc.Height = mSize.height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_D32_FLOAT;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
+
+ RefPtr<ID3D11Texture2D> buffer;
+ HRESULT hr = aDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(buffer));
+ if (FAILED(hr) || !buffer) {
+ gfxCriticalNote << "Could not create depth-stencil buffer: " << hexa(hr);
+ return false;
+ }
+
+ D3D11_DEPTH_STENCIL_VIEW_DESC viewDesc;
+ ::ZeroMemory(&viewDesc, sizeof(viewDesc));
+ viewDesc.Format = DXGI_FORMAT_D32_FLOAT;
+ viewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
+
+ RefPtr<ID3D11DepthStencilView> dsv;
+ hr = aDevice->CreateDepthStencilView(buffer, &viewDesc, getter_AddRefs(dsv));
+ if (FAILED(hr) || !dsv) {
+ gfxCriticalNote << "Could not create depth-stencil view: " << hexa(hr);
+ return false;
+ }
+
+ mDepthBuffer = buffer;
+ mDepthStencilView = dsv;
+ sRenderTargetUsage += mSize.width * mSize.height * 1;
+ return true;
+}
+
+ID3D11DepthStencilView* MLGRenderTargetD3D11::GetDSV() {
+ return mDepthStencilView;
+}
+
+ID3D11RenderTargetView* MLGRenderTargetD3D11::GetRenderTargetView() {
+ return mRTView;
+}
+
+IntSize MLGRenderTargetD3D11::GetSize() const { return mSize; }
+
+MLGTexture* MLGRenderTargetD3D11::GetTexture() {
+ if (!mTextureSource) {
+ mTextureSource = new MLGTextureD3D11(mTexture);
+ }
+ return mTextureSource;
+}
+
+MLGSwapChainD3D11::MLGSwapChainD3D11(MLGDeviceD3D11* aParent,
+ ID3D11Device* aDevice)
+ : mParent(aParent),
+ mDevice(aDevice),
+ mWidget(nullptr),
+ mCanUsePartialPresents(CanUsePartialPresents(aDevice)) {}
+
+MLGSwapChainD3D11::~MLGSwapChainD3D11() {}
+
+void MLGSwapChainD3D11::Destroy() {
+ if (mRT == mParent->GetRenderTarget()) {
+ mParent->SetRenderTarget(nullptr);
+ }
+ mWidget = nullptr;
+ mRT = nullptr;
+ mSwapChain = nullptr;
+ mSwapChain1 = nullptr;
+}
+
+RefPtr<MLGSwapChainD3D11> MLGSwapChainD3D11::Create(MLGDeviceD3D11* aParent,
+ ID3D11Device* aDevice,
+ CompositorWidget* aWidget) {
+ RefPtr<MLGSwapChainD3D11> swapChain = new MLGSwapChainD3D11(aParent, aDevice);
+ if (!swapChain->Initialize(aWidget)) {
+ return nullptr;
+ }
+ return swapChain.forget();
+}
+
+bool MLGSwapChainD3D11::Initialize(CompositorWidget* aWidget) {
+ HWND hwnd = aWidget->AsWindows()->GetHwnd();
+
+ RefPtr<IDXGIDevice> dxgiDevice;
+ mDevice->QueryInterface(dxgiDevice.StartAssignment());
+
+ RefPtr<IDXGIFactory> dxgiFactory;
+ {
+ RefPtr<IDXGIAdapter> adapter;
+ dxgiDevice->GetAdapter(getter_AddRefs(adapter));
+
+ adapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment()));
+ }
+
+ RefPtr<IDXGIFactory2> dxgiFactory2;
+ if (gfxVars::UseDoubleBufferingWithCompositor() &&
+ SUCCEEDED(dxgiFactory->QueryInterface(dxgiFactory2.StartAssignment())) &&
+ dxgiFactory2 && XRE_IsGPUProcess()) {
+ // DXGI_SCALING_NONE is not available on Windows 7 with the Platform Update:
+ // This looks awful for things like the awesome bar and browser window
+ // resizing, so we don't use a flip buffer chain here. (Note when using
+ // EFFECT_SEQUENTIAL Windows doesn't stretch the surface when resizing).
+ //
+ // We choose not to run this on platforms earlier than Windows 10 because
+ // it appears sometimes this breaks our ability to test ASAP compositing,
+ // which breaks Talos.
+ //
+ // When the GPU process is disabled we don't have a compositor window which
+ // can lead to issues with Window re-use so we don't use this.
+ DXGI_SWAP_CHAIN_DESC1 desc;
+ ::ZeroMemory(&desc, sizeof(desc));
+ desc.Width = 0;
+ desc.Height = 0;
+ desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ desc.BufferCount = 2;
+ desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+ desc.Scaling = DXGI_SCALING_NONE;
+ desc.Flags = 0;
+
+ HRESULT hr = dxgiFactory2->CreateSwapChainForHwnd(
+ mDevice, hwnd, &desc, nullptr, nullptr, getter_AddRefs(mSwapChain1));
+ if (SUCCEEDED(hr) && mSwapChain1) {
+ DXGI_RGBA color = {1.0f, 1.0f, 1.0f, 1.0f};
+ mSwapChain1->SetBackgroundColor(&color);
+ mSwapChain = mSwapChain1;
+ mIsDoubleBuffered = true;
+ } else if (aWidget->AsWindows()->GetCompositorHwnd()) {
+ // Destroy compositor window.
+ aWidget->AsWindows()->DestroyCompositorWindow();
+ hwnd = aWidget->AsWindows()->GetHwnd();
+ }
+ }
+
+ if (!mSwapChain) {
+ DXGI_SWAP_CHAIN_DESC swapDesc;
+ ::ZeroMemory(&swapDesc, sizeof(swapDesc));
+ swapDesc.BufferDesc.Width = 0;
+ swapDesc.BufferDesc.Height = 0;
+ swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+ swapDesc.BufferDesc.RefreshRate.Numerator = 60;
+ swapDesc.BufferDesc.RefreshRate.Denominator = 1;
+ swapDesc.SampleDesc.Count = 1;
+ swapDesc.SampleDesc.Quality = 0;
+ swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapDesc.BufferCount = 1;
+ swapDesc.OutputWindow = hwnd;
+ swapDesc.Windowed = TRUE;
+ swapDesc.Flags = 0;
+ swapDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
+
+ HRESULT hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc,
+ getter_AddRefs(mSwapChain));
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Could not create swap chain: " << hexa(hr);
+ return false;
+ }
+
+ // Try to get an IDXGISwapChain1 if we can, for partial presents.
+ mSwapChain->QueryInterface(mSwapChain1.StartAssignment());
+ }
+
+ // We need this because we don't want DXGI to respond to Alt+Enter.
+ dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
+ mWidget = aWidget;
+ return true;
+}
+
+RefPtr<MLGRenderTarget> MLGSwapChainD3D11::AcquireBackBuffer() {
+ RefPtr<ID3D11Texture2D> texture;
+ HRESULT hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
+ getter_AddRefs(texture));
+ if (hr == DXGI_ERROR_INVALID_CALL &&
+ mDevice->GetDeviceRemovedReason() != S_OK) {
+ // This can happen on some drivers when there's a TDR.
+ mParent->HandleDeviceReset("SwapChain::GetBuffer");
+ return nullptr;
+ }
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Failed to acquire swap chain's backbuffer: "
+ << hexa(hr);
+ return nullptr;
+ }
+
+ if (!mRT) {
+ MLGRenderTargetFlags flags = MLGRenderTargetFlags::Default;
+ if (StaticPrefs::layers_mlgpu_enable_depth_buffer_AtStartup()) {
+ flags |= MLGRenderTargetFlags::ZBuffer;
+ }
+
+ mRT = new MLGRenderTargetD3D11(mSize, flags);
+ if (!mRT->Initialize(mDevice, nullptr)) {
+ return nullptr;
+ }
+ }
+
+ if (!mRT->UpdateTexture(texture)) {
+ return nullptr;
+ }
+
+ if (mIsDoubleBuffered) {
+ UpdateBackBufferContents(texture);
+ }
+ return mRT;
+}
+
+void MLGSwapChainD3D11::UpdateBackBufferContents(ID3D11Texture2D* aBack) {
+ MOZ_ASSERT(mIsDoubleBuffered);
+
+ // The front region contains the newly invalid region for this frame. The
+ // back region contains that, plus the region that was only drawn into the
+ // back buffer on the previous frame. Thus by subtracting the two, we can
+ // find the region that needs to be copied from the front buffer to the
+ // back. We do this so we don't have to re-render those pixels.
+ nsIntRegion frontValid;
+ frontValid.Sub(mBackBufferInvalid, mFrontBufferInvalid);
+ if (frontValid.IsEmpty()) {
+ return;
+ }
+
+ RefPtr<ID3D11Texture2D> front;
+ HRESULT hr = mSwapChain->GetBuffer(1, __uuidof(ID3D11Texture2D),
+ getter_AddRefs(front));
+ if (FAILED(hr) || !front) {
+ return;
+ }
+
+ RefPtr<ID3D11DeviceContext> context;
+ mDevice->GetImmediateContext(getter_AddRefs(context));
+
+ for (auto iter = frontValid.RectIter(); !iter.Done(); iter.Next()) {
+ const IntRect& rect = iter.Get();
+ D3D11_BOX box = RectToBox(rect);
+ context->CopySubresourceRegion(aBack, 0, rect.X(), rect.Y(), 0, front, 0,
+ &box);
+ }
+
+ // The back and front buffers are now in sync.
+ mBackBufferInvalid = mFrontBufferInvalid;
+ MOZ_ASSERT(!mBackBufferInvalid.IsEmpty());
+}
+
+bool MLGSwapChainD3D11::ResizeBuffers(const IntSize& aSize) {
+ // We have to clear all references to the old backbuffer before resizing.
+ mRT = nullptr;
+
+ // Clear the size before re-allocating. If allocation fails we want to try
+ // again, because we had to sacrifice our original backbuffer to try
+ // resizing.
+ mSize = IntSize(0, 0);
+
+ HRESULT hr = mSwapChain->ResizeBuffers(0, aSize.width, aSize.height,
+ DXGI_FORMAT_B8G8R8A8_UNORM, 0);
+ if (hr == DXGI_ERROR_DEVICE_REMOVED) {
+ mParent->HandleDeviceReset("ResizeBuffers");
+ return false;
+ }
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Failed to resize swap chain buffers: " << hexa(hr);
+ return false;
+ }
+
+ mSize = aSize;
+ mBackBufferInvalid = IntRect(IntPoint(0, 0), mSize);
+ mFrontBufferInvalid = IntRect(IntPoint(0, 0), mSize);
+ return true;
+}
+
+IntSize MLGSwapChainD3D11::GetSize() const { return mSize; }
+
+void MLGSwapChainD3D11::Present() {
+ MOZ_ASSERT(!mBackBufferInvalid.IsEmpty());
+ MOZ_ASSERT(mBackBufferInvalid.GetNumRects() > 0);
+
+ // See bug 1260611 comment #28 for why we do this.
+ mParent->InsertPresentWaitQuery();
+
+ if (mWidget->AsWindows()->HasFxrOutputHandler()) {
+ // There is a Firefox Reality handler for this swapchain. Update this
+ // window's contents to the VR window.
+ FxROutputHandler* fxrHandler = mWidget->AsWindows()->GetFxrOutputHandler();
+ if (fxrHandler->TryInitialize(mSwapChain, mDevice)) {
+ RefPtr<ID3D11DeviceContext> context;
+ mDevice->GetImmediateContext(getter_AddRefs(context));
+ fxrHandler->UpdateOutput(context);
+ }
+ }
+
+ HRESULT hr;
+ if (mCanUsePartialPresents && mSwapChain1) {
+ StackArray<RECT, 4> rects(mBackBufferInvalid.GetNumRects());
+ size_t i = 0;
+ for (auto iter = mBackBufferInvalid.RectIter(); !iter.Done(); iter.Next()) {
+ const IntRect& rect = iter.Get();
+ rects[i].left = rect.X();
+ rects[i].top = rect.Y();
+ rects[i].bottom = rect.YMost();
+ rects[i].right = rect.XMost();
+ i++;
+ }
+
+ DXGI_PRESENT_PARAMETERS params;
+ PodZero(&params);
+ params.DirtyRectsCount = mBackBufferInvalid.GetNumRects();
+ params.pDirtyRects = rects.data();
+ hr = mSwapChain1->Present1(0, 0, &params);
+ } else {
+ hr = mSwapChain->Present(0, 0);
+ }
+
+ if (hr == DXGI_ERROR_DEVICE_REMOVED) {
+ mParent->HandleDeviceReset("Present");
+ }
+
+ if (FAILED(hr)) {
+ gfxCriticalNote << "D3D11 swap chain failed to present: " << hexa(hr);
+ }
+
+ if (mIsDoubleBuffered) {
+ // Both the front and back buffer invalid regions are in sync, but now the
+ // presented buffer (the front buffer) is clean, so we clear its invalid
+ // region. The back buffer that will be used next frame however is now
+ // dirty.
+ MOZ_ASSERT(mFrontBufferInvalid.GetBounds() ==
+ mBackBufferInvalid.GetBounds());
+ mFrontBufferInvalid.SetEmpty();
+ } else {
+ mBackBufferInvalid.SetEmpty();
+ }
+ mLastPresentSize = mSize;
+
+ // Note: this waits on the query we inserted in the previous frame,
+ // not the one we just inserted now. Example:
+ // Insert query #1
+ // Present #1
+ // (first frame, no wait)
+ // Insert query #2
+ // Present #2
+ // Wait for query #1.
+ // Insert query #3
+ // Present #3
+ // Wait for query #2.
+ //
+ // This ensures we're done reading textures before swapping buffers.
+ mParent->WaitForPreviousPresentQuery();
+}
+
+void MLGSwapChainD3D11::ForcePresent() {
+ DXGI_SWAP_CHAIN_DESC desc;
+ mSwapChain->GetDesc(&desc);
+
+ LayoutDeviceIntSize size = mWidget->GetClientSize();
+
+ if (desc.BufferDesc.Width != size.width ||
+ desc.BufferDesc.Height != size.height) {
+ return;
+ }
+
+ mSwapChain->Present(0, 0);
+ if (mIsDoubleBuffered) {
+ // Make sure we present the old front buffer since we know it is completely
+ // valid. This non-vsynced present should be pretty much 'free' for a flip
+ // chain.
+ mSwapChain->Present(0, 0);
+ }
+
+ mLastPresentSize = mSize;
+}
+
+void MLGSwapChainD3D11::CopyBackbuffer(gfx::DrawTarget* aTarget,
+ const gfx::IntRect& aBounds) {
+ RefPtr<ID3D11DeviceContext> context;
+ mDevice->GetImmediateContext(getter_AddRefs(context));
+
+ RefPtr<ID3D11Texture2D> backbuffer;
+ HRESULT hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
+ (void**)backbuffer.StartAssignment());
+ if (FAILED(hr)) {
+ gfxWarning() << "Failed to acquire swapchain backbuffer: " << hexa(hr);
+ return;
+ }
+
+ D3D11_TEXTURE2D_DESC bbDesc;
+ backbuffer->GetDesc(&bbDesc);
+
+ CD3D11_TEXTURE2D_DESC tempDesc(bbDesc.Format, bbDesc.Width, bbDesc.Height);
+ tempDesc.MipLevels = 1;
+ tempDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ tempDesc.Usage = D3D11_USAGE_STAGING;
+ tempDesc.BindFlags = 0;
+
+ RefPtr<ID3D11Texture2D> temp;
+ hr = mDevice->CreateTexture2D(&tempDesc, nullptr, getter_AddRefs(temp));
+ if (FAILED(hr)) {
+ gfxWarning() << "Failed to create a temporary texture for PresentAndCopy: "
+ << hexa(hr);
+ return;
+ }
+
+ context->CopyResource(temp, backbuffer);
+
+ D3D11_MAPPED_SUBRESOURCE map;
+ hr = context->Map(temp, 0, D3D11_MAP_READ, 0, &map);
+ if (FAILED(hr)) {
+ gfxWarning() << "Failed to map temporary texture for PresentAndCopy: "
+ << hexa(hr);
+ return;
+ }
+
+ RefPtr<DataSourceSurface> source = Factory::CreateWrappingDataSourceSurface(
+ (uint8_t*)map.pData, map.RowPitch, IntSize(bbDesc.Width, bbDesc.Height),
+ SurfaceFormat::B8G8R8A8);
+
+ aTarget->CopySurface(source, IntRect(0, 0, bbDesc.Width, bbDesc.Height),
+ IntPoint(-aBounds.X(), -aBounds.Y()));
+ aTarget->Flush();
+
+ context->Unmap(temp, 0);
+}
+
+RefPtr<MLGBufferD3D11> MLGBufferD3D11::Create(ID3D11Device* aDevice,
+ MLGBufferType aType,
+ uint32_t aSize, MLGUsage aUsage,
+ const void* aInitialData) {
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = aSize;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+
+ switch (aUsage) {
+ case MLGUsage::Dynamic:
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ break;
+ case MLGUsage::Immutable:
+ desc.Usage = D3D11_USAGE_IMMUTABLE;
+ desc.CPUAccessFlags = 0;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown buffer usage type");
+ return nullptr;
+ }
+
+ switch (aType) {
+ case MLGBufferType::Vertex:
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ break;
+ case MLGBufferType::Constant:
+ desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown buffer type");
+ return nullptr;
+ }
+
+ D3D11_SUBRESOURCE_DATA data;
+ data.pSysMem = aInitialData;
+ data.SysMemPitch = aSize;
+ data.SysMemSlicePitch = 0;
+
+ RefPtr<ID3D11Buffer> buffer;
+ HRESULT hr = aDevice->CreateBuffer(&desc, aInitialData ? &data : nullptr,
+ getter_AddRefs(buffer));
+ if (FAILED(hr) || !buffer) {
+ gfxCriticalError() << "Failed to create ID3D11Buffer.";
+ return nullptr;
+ }
+
+ return new MLGBufferD3D11(buffer, aType, aSize);
+}
+
+MLGBufferD3D11::MLGBufferD3D11(ID3D11Buffer* aBuffer, MLGBufferType aType,
+ size_t aSize)
+ : mBuffer(aBuffer), mType(aType), mSize(aSize) {
+ switch (mType) {
+ case MLGBufferType::Vertex:
+ mlg::sVertexBufferUsage += mSize;
+ break;
+ case MLGBufferType::Constant:
+ mlg::sConstantBufferUsage += mSize;
+ break;
+ }
+}
+
+MLGBufferD3D11::~MLGBufferD3D11() {
+ switch (mType) {
+ case MLGBufferType::Vertex:
+ mlg::sVertexBufferUsage -= mSize;
+ break;
+ case MLGBufferType::Constant:
+ mlg::sConstantBufferUsage -= mSize;
+ break;
+ }
+}
+
+MLGTextureD3D11::MLGTextureD3D11(ID3D11Texture2D* aTexture)
+ : mTexture(aTexture) {
+ D3D11_TEXTURE2D_DESC desc;
+ aTexture->GetDesc(&desc);
+
+ mSize.width = desc.Width;
+ mSize.height = desc.Height;
+}
+
+/* static */
+RefPtr<MLGTextureD3D11> MLGTextureD3D11::Create(ID3D11Device* aDevice,
+ const gfx::IntSize& aSize,
+ gfx::SurfaceFormat aFormat,
+ MLGUsage aUsage,
+ MLGTextureFlags aFlags) {
+ D3D11_TEXTURE2D_DESC desc;
+ ::ZeroMemory(&desc, sizeof(desc));
+ desc.Width = aSize.width;
+ desc.Height = aSize.height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.SampleDesc.Count = 1;
+
+ switch (aFormat) {
+ case SurfaceFormat::B8G8R8A8:
+ desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unsupported surface format");
+ return nullptr;
+ }
+
+ switch (aUsage) {
+ case MLGUsage::Immutable:
+ desc.Usage = D3D11_USAGE_IMMUTABLE;
+ break;
+ case MLGUsage::Default:
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ break;
+ case MLGUsage::Dynamic:
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ break;
+ case MLGUsage::Staging:
+ desc.Usage = D3D11_USAGE_STAGING;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unsupported usage type");
+ break;
+ }
+
+ if (aFlags & MLGTextureFlags::ShaderResource) {
+ desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
+ }
+ if (aFlags & MLGTextureFlags::RenderTarget) {
+ desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
+ }
+
+ RefPtr<ID3D11Texture2D> texture;
+ HRESULT hr =
+ aDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
+ if (FAILED(hr) || !texture) {
+ gfxCriticalNote << "Failed to create 2D texture: " << hexa(hr);
+ return nullptr;
+ }
+
+ ReportTextureMemoryUsage(texture, aSize.width * aSize.height * 4);
+
+ return new MLGTextureD3D11(texture);
+}
+
+ID3D11ShaderResourceView* MLGTextureD3D11::GetShaderResourceView() {
+ if (!mView) {
+ RefPtr<ID3D11Device> device;
+ mTexture->GetDevice(getter_AddRefs(device));
+
+ HRESULT hr = device->CreateShaderResourceView(mTexture, nullptr,
+ getter_AddRefs(mView));
+ if (FAILED(hr) || !mView) {
+ gfxWarning() << "Could not create shader resource view: " << hexa(hr);
+ return nullptr;
+ }
+ }
+ return mView;
+}
+
+MLGDeviceD3D11::MLGDeviceD3D11(ID3D11Device* aDevice)
+ : mDevice(aDevice), mScissored(false) {}
+
+MLGDeviceD3D11::~MLGDeviceD3D11() {
+ // Caller should have unlocked all textures after presenting.
+ MOZ_ASSERT(mLockedTextures.IsEmpty());
+ MOZ_ASSERT(mLockAttemptedTextures.IsEmpty());
+}
+
+bool MLGDeviceD3D11::Initialize() {
+ if (!mDevice) {
+ return Fail("FEATURE_FAILURE_NO_DEVICE");
+ }
+
+ if (mDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
+ return Fail("FEATURE_FAILURE_NEED_LEVEL_10_0");
+ }
+
+ mDevice->GetImmediateContext(getter_AddRefs(mCtx));
+ if (!mCtx) {
+ return Fail("FEATURE_FAILURE_NO_CONTEXT");
+ }
+
+ mCtx->QueryInterface((ID3D11DeviceContext1**)getter_AddRefs(mCtx1));
+
+ if (mCtx1) {
+ // Windows 7 can have Direct3D 11.1 if the platform update is installed,
+ // but according to some NVIDIA presentations it is known to be buggy.
+ // It's not clear whether that only refers to command list emulation,
+ // or whether it just has performance penalties. To be safe we only use
+ // it on Windows 8 or higher.
+ //
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/directx-feature-improvements-in-windows-8#buffers
+ D3D11_FEATURE_DATA_D3D11_OPTIONS options;
+ HRESULT hr = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS,
+ &options, sizeof(options));
+ if (SUCCEEDED(hr)) {
+ if (IsWin8OrLater()) {
+ mCanUseConstantBufferOffsetBinding =
+ (options.ConstantBufferOffsetting != FALSE);
+ } else {
+ gfxConfig::EnableFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING,
+ "Unsupported by driver");
+ }
+ mCanUseClearView = (options.ClearView != FALSE);
+ } else {
+ gfxCriticalNote << "Failed to query D3D11.1 feature support: "
+ << hexa(hr);
+ }
+ }
+
+ // Get capabilities.
+ switch (mDevice->GetFeatureLevel()) {
+ case D3D_FEATURE_LEVEL_11_1:
+ case D3D_FEATURE_LEVEL_11_0:
+ mMaxConstantBufferBindSize = D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16;
+ break;
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ mMaxConstantBufferBindSize = D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown feature level");
+ }
+
+ mDiagnostics = MakeUnique<DiagnosticsD3D11>(mDevice, mCtx);
+
+ {
+ struct Vertex2D {
+ float x;
+ float y;
+ };
+ Vertex2D vertices[] = {{0, 0}, {1.0f, 0}, {0, 1.0f}, {1.0f, 1.0f}};
+ mUnitQuadVB = CreateBuffer(MLGBufferType::Vertex, sizeof(Vertex2D) * 4,
+ MLGUsage::Immutable, &vertices);
+ if (!mUnitQuadVB) {
+ return Fail("FEATURE_FAILURE_UNIT_QUAD_BUFFER");
+ }
+ }
+
+ {
+ struct Vertex3D {
+ float x;
+ float y;
+ float z;
+ };
+ Vertex3D vertices[3] = {
+ {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
+ mUnitTriangleVB = CreateBuffer(MLGBufferType::Vertex, sizeof(Vertex3D) * 3,
+ MLGUsage::Immutable, &vertices);
+ if (!mUnitTriangleVB) {
+ return Fail("FEATURE_FAILURE_UNIT_TRIANGLE_BUFFER");
+ }
+ }
+
+ // Define pixel shaders.
+#define LAZY_PS(cxxName, enumName) \
+ mLazyPixelShaders[PixelShaderID::enumName] = &s##cxxName;
+ LAZY_PS(TexturedVertexRGB, TexturedVertexRGB);
+ LAZY_PS(TexturedVertexRGBA, TexturedVertexRGBA);
+ LAZY_PS(TexturedQuadRGB, TexturedQuadRGB);
+ LAZY_PS(TexturedQuadRGBA, TexturedQuadRGBA);
+ LAZY_PS(ColoredQuadPS, ColoredQuad);
+ LAZY_PS(ColoredVertexPS, ColoredVertex);
+ LAZY_PS(ComponentAlphaQuadPS, ComponentAlphaQuad);
+ LAZY_PS(ComponentAlphaVertexPS, ComponentAlphaVertex);
+ LAZY_PS(TexturedVertexIMC4, TexturedVertexIMC4);
+ LAZY_PS(TexturedVertexIdentityIMC4, TexturedVertexIdentityIMC4);
+ LAZY_PS(TexturedVertexNV12, TexturedVertexNV12);
+ LAZY_PS(TexturedQuadIMC4, TexturedQuadIMC4);
+ LAZY_PS(TexturedQuadIdentityIMC4, TexturedQuadIdentityIMC4);
+ LAZY_PS(TexturedQuadNV12, TexturedQuadNV12);
+ LAZY_PS(BlendMultiplyPS, BlendMultiply);
+ LAZY_PS(BlendScreenPS, BlendScreen);
+ LAZY_PS(BlendOverlayPS, BlendOverlay);
+ LAZY_PS(BlendDarkenPS, BlendDarken);
+ LAZY_PS(BlendLightenPS, BlendLighten);
+ LAZY_PS(BlendColorDodgePS, BlendColorDodge);
+ LAZY_PS(BlendColorBurnPS, BlendColorBurn);
+ LAZY_PS(BlendHardLightPS, BlendHardLight);
+ LAZY_PS(BlendSoftLightPS, BlendSoftLight);
+ LAZY_PS(BlendDifferencePS, BlendDifference);
+ LAZY_PS(BlendExclusionPS, BlendExclusion);
+ LAZY_PS(BlendHuePS, BlendHue);
+ LAZY_PS(BlendSaturationPS, BlendSaturation);
+ LAZY_PS(BlendColorPS, BlendColor);
+ LAZY_PS(BlendLuminosityPS, BlendLuminosity);
+ LAZY_PS(ClearPS, Clear);
+ LAZY_PS(MaskCombinerPS, MaskCombiner);
+ LAZY_PS(DiagnosticTextPS, DiagnosticText);
+#undef LAZY_PS
+
+ // Define vertex shaders.
+#define LAZY_VS(cxxName, enumName) \
+ mLazyVertexShaders[VertexShaderID::enumName] = &s##cxxName;
+ LAZY_VS(TexturedQuadVS, TexturedQuad);
+ LAZY_VS(TexturedVertexVS, TexturedVertex);
+ LAZY_VS(BlendVertexVS, BlendVertex);
+ LAZY_VS(ColoredQuadVS, ColoredQuad);
+ LAZY_VS(ColoredVertexVS, ColoredVertex);
+ LAZY_VS(ClearVS, Clear);
+ LAZY_VS(MaskCombinerVS, MaskCombiner);
+ LAZY_VS(DiagnosticTextVS, DiagnosticText);
+#undef LAZY_VS
+
+ // Force critical shaders to initialize early.
+ if (!InitPixelShader(PixelShaderID::TexturedQuadRGB) ||
+ !InitPixelShader(PixelShaderID::TexturedQuadRGBA) ||
+ !InitPixelShader(PixelShaderID::ColoredQuad) ||
+ !InitPixelShader(PixelShaderID::ComponentAlphaQuad) ||
+ !InitPixelShader(PixelShaderID::Clear) ||
+ !InitVertexShader(VertexShaderID::TexturedQuad) ||
+ !InitVertexShader(VertexShaderID::ColoredQuad) ||
+ !InitVertexShader(VertexShaderID::Clear)) {
+ return Fail("FEATURE_FAILURE_CRITICAL_SHADER_FAILURE");
+ }
+
+ // Common unit quad layout: vPos, vRect, vLayerIndex, vDepth
+#define BASE_UNIT_QUAD_LAYOUT \
+ {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, \
+ 0}, \
+ {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, \
+ 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, \
+ 1}, \
+ {"TEXCOORD", \
+ 1, \
+ DXGI_FORMAT_R32_UINT, \
+ 1, \
+ D3D11_APPEND_ALIGNED_ELEMENT, \
+ D3D11_INPUT_PER_INSTANCE_DATA, \
+ 1}, \
+ { \
+ "TEXCOORD", 2, DXGI_FORMAT_R32_SINT, 1, D3D11_APPEND_ALIGNED_ELEMENT, \
+ D3D11_INPUT_PER_INSTANCE_DATA, 1 \
+ }
+
+ // Common unit triangle layout: vUnitPos, vPos1-3, vLayerIndex, vDepth
+#define BASE_UNIT_TRIANGLE_LAYOUT \
+ {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, \
+ 0, 0, D3D11_INPUT_PER_VERTEX_DATA, \
+ 0}, \
+ {"POSITION", 1, DXGI_FORMAT_R32G32_FLOAT, \
+ 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, \
+ 1}, \
+ {"POSITION", \
+ 2, \
+ DXGI_FORMAT_R32G32_FLOAT, \
+ 1, \
+ D3D11_APPEND_ALIGNED_ELEMENT, \
+ D3D11_INPUT_PER_INSTANCE_DATA, \
+ 1}, \
+ {"POSITION", \
+ 3, \
+ DXGI_FORMAT_R32G32_FLOAT, \
+ 1, \
+ D3D11_APPEND_ALIGNED_ELEMENT, \
+ D3D11_INPUT_PER_INSTANCE_DATA, \
+ 1}, \
+ {"TEXCOORD", \
+ 0, \
+ DXGI_FORMAT_R32_UINT, \
+ 1, \
+ D3D11_APPEND_ALIGNED_ELEMENT, \
+ D3D11_INPUT_PER_INSTANCE_DATA, \
+ 1}, \
+ {"TEXCOORD", \
+ 1, \
+ DXGI_FORMAT_R32_SINT, \
+ 1, \
+ D3D11_APPEND_ALIGNED_ELEMENT, \
+ D3D11_INPUT_PER_INSTANCE_DATA, \
+ 1}
+
+ // Initialize input layouts.
+ {
+ D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
+ BASE_UNIT_QUAD_LAYOUT,
+ // vTexRect
+ {"TEXCOORD", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
+ D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
+ if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
+ sTexturedQuadVS, VertexShaderID::TexturedQuad)) {
+ return Fail("FEATURE_FAILURE_UNIT_QUAD_TEXTURED_LAYOUT");
+ }
+ }
+ {
+ D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
+ BASE_UNIT_QUAD_LAYOUT,
+ // vColor
+ {"TEXCOORD", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
+ D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
+ if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc), sColoredQuadVS,
+ VertexShaderID::ColoredQuad)) {
+ return Fail("FEATURE_FAILURE_UNIT_QUAD_COLORED_LAYOUT");
+ }
+ }
+ {
+ D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
+ BASE_UNIT_TRIANGLE_LAYOUT,
+ // vTexCoord1, vTexCoord2, vTexCoord3
+ {"TEXCOORD", 2, DXGI_FORMAT_R32G32_FLOAT, 1,
+ D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
+ {"TEXCOORD", 3, DXGI_FORMAT_R32G32_FLOAT, 1,
+ D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
+ {"TEXCOORD", 4, DXGI_FORMAT_R32G32_FLOAT, 1,
+ D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
+ if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
+ sTexturedVertexVS, VertexShaderID::TexturedVertex)) {
+ return Fail("FEATURE_FAILURE_TEXTURED_INPUT_LAYOUT");
+ }
+ // Propagate the input layout to other vertex shaders that use the same.
+ mInputLayouts[VertexShaderID::BlendVertex] =
+ mInputLayouts[VertexShaderID::TexturedVertex];
+ }
+ {
+ D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
+ BASE_UNIT_TRIANGLE_LAYOUT,
+ {"TEXCOORD", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
+ D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
+ if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
+ sColoredVertexVS, VertexShaderID::ColoredVertex)) {
+ return Fail("FEATURE_FAILURE_COLORED_INPUT_LAYOUT");
+ }
+ }
+
+#undef BASE_UNIT_QUAD_LAYOUT
+#undef BASE_UNIT_TRIANGLE_LAYOUT
+
+ // Ancillary shaders that are not used for batching.
+ {
+ D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
+ // vPos
+ {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
+ D3D11_INPUT_PER_VERTEX_DATA, 0},
+ // vRect
+ {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_SINT, 1, 0,
+ D3D11_INPUT_PER_INSTANCE_DATA, 1},
+ // vDepth
+ {"TEXCOORD", 1, DXGI_FORMAT_R32_SINT, 1, D3D11_APPEND_ALIGNED_ELEMENT,
+ D3D11_INPUT_PER_INSTANCE_DATA, 1},
+ };
+ if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc), sClearVS,
+ VertexShaderID::Clear)) {
+ return Fail("FEATURE_FAILURE_CLEAR_INPUT_LAYOUT");
+ }
+ }
+ {
+ D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
+ // vPos
+ {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
+ D3D11_INPUT_PER_VERTEX_DATA, 0},
+ // vTexCoords
+ {"POSITION", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
+ D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
+ if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
+ sMaskCombinerVS, VertexShaderID::MaskCombiner)) {
+ return Fail("FEATURE_FAILURE_MASK_COMBINER_INPUT_LAYOUT");
+ }
+ }
+ {
+ D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
+ // vPos
+ {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
+ D3D11_INPUT_PER_VERTEX_DATA, 0},
+ // vRect
+ {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0,
+ D3D11_INPUT_PER_INSTANCE_DATA, 1},
+ // vTexCoords
+ {"TEXCOORD", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
+ D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
+ };
+ if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
+ sDiagnosticTextVS, VertexShaderID::DiagnosticText)) {
+ return Fail("FEATURE_FAILURE_DIAGNOSTIC_INPUT_LAYOUT");
+ }
+ }
+
+ if (!InitRasterizerStates() || !InitDepthStencilState() ||
+ !InitBlendStates() || !InitSamplerStates() || !InitSyncObject()) {
+ return false;
+ }
+
+ mCtx->RSSetState(mRasterizerStateNoScissor);
+
+ return MLGDevice::Initialize();
+}
+
+bool MLGDeviceD3D11::InitPixelShader(PixelShaderID aShaderID) {
+ const ShaderBytes* code = mLazyPixelShaders[aShaderID];
+ HRESULT hr =
+ mDevice->CreatePixelShader(code->mData, code->mLength, nullptr,
+ getter_AddRefs(mPixelShaders[aShaderID]));
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Could not create pixel shader "
+ << hexa(unsigned(aShaderID)) << ": " << hexa(hr);
+ return false;
+ }
+ return true;
+}
+
+bool MLGDeviceD3D11::InitRasterizerStates() {
+ {
+ CD3D11_RASTERIZER_DESC desc = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
+ desc.CullMode = D3D11_CULL_NONE;
+ desc.FillMode = D3D11_FILL_SOLID;
+ desc.ScissorEnable = TRUE;
+ HRESULT hr = mDevice->CreateRasterizerState(
+ &desc, getter_AddRefs(mRasterizerStateScissor));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_SCISSOR_RASTERIZER",
+ "Could not create scissor rasterizer (%x)", hr);
+ }
+ }
+ {
+ CD3D11_RASTERIZER_DESC desc = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
+ desc.CullMode = D3D11_CULL_NONE;
+ desc.FillMode = D3D11_FILL_SOLID;
+ HRESULT hr = mDevice->CreateRasterizerState(
+ &desc, getter_AddRefs(mRasterizerStateNoScissor));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_DEFAULT_RASTERIZER",
+ "Could not create default rasterizer (%x)", hr);
+ }
+ }
+ return true;
+}
+
+bool MLGDeviceD3D11::InitSamplerStates() {
+ {
+ CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
+ HRESULT hr = mDevice->CreateSamplerState(
+ &desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearClamp]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_LINEAR_CLAMP_SAMPLER",
+ "Could not create linear clamp sampler (%x)", hr);
+ }
+ }
+ {
+ CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
+ memset(desc.BorderColor, 0, sizeof(desc.BorderColor));
+ HRESULT hr = mDevice->CreateSamplerState(
+ &desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearClampToZero]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_LINEAR_CLAMP_ZERO_SAMPLER",
+ "Could not create linear clamp to zero sampler (%x)", hr);
+ }
+ }
+ {
+ CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+ HRESULT hr = mDevice->CreateSamplerState(
+ &desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearRepeat]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_LINEAR_CLAMP_ZERO_SAMPLER",
+ "Could not create linear clamp to zero sampler (%x)", hr);
+ }
+ }
+
+ {
+ CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+ HRESULT hr = mDevice->CreateSamplerState(
+ &desc, getter_AddRefs(mSamplerStates[SamplerMode::Point]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_POINT_SAMPLER",
+ "Could not create point sampler (%x)", hr);
+ }
+ }
+ return true;
+}
+
+bool MLGDeviceD3D11::InitBlendStates() {
+ {
+ CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
+ HRESULT hr = mDevice->CreateBlendState(
+ &desc, getter_AddRefs(mBlendStates[MLGBlendState::Copy]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_COPY_BLEND_STATE",
+ "Could not create copy blend state (%x)", hr);
+ }
+ }
+
+ {
+ CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
+ desc.RenderTarget[0].BlendEnable = TRUE;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ HRESULT hr = mDevice->CreateBlendState(
+ &desc, getter_AddRefs(mBlendStates[MLGBlendState::Over]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_OVER_BLEND_STATE",
+ "Could not create over blend state (%x)", hr);
+ }
+ }
+
+ {
+ CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
+ desc.RenderTarget[0].BlendEnable = TRUE;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ HRESULT hr = mDevice->CreateBlendState(
+ &desc, getter_AddRefs(mBlendStates[MLGBlendState::OverAndPremultiply]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_OVER_BLEND_STATE",
+ "Could not create over blend state (%x)", hr);
+ }
+ }
+
+ {
+ CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
+ desc.RenderTarget[0].BlendEnable = TRUE;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_MIN;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_MIN;
+ HRESULT hr = mDevice->CreateBlendState(
+ &desc, getter_AddRefs(mBlendStates[MLGBlendState::Min]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_MIN_BLEND_STATE",
+ "Could not create min blend state (%x)", hr);
+ }
+ }
+
+ {
+ CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
+ desc.RenderTarget[0].BlendEnable = TRUE;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_COLOR;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ HRESULT hr = mDevice->CreateBlendState(
+ &desc, getter_AddRefs(mBlendStates[MLGBlendState::ComponentAlpha]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_COMPONENT_ALPHA_BLEND_STATE",
+ "Could not create component alpha blend state (%x)", hr);
+ }
+ }
+ return true;
+}
+
+bool MLGDeviceD3D11::InitDepthStencilState() {
+ D3D11_DEPTH_STENCIL_DESC desc = CD3D11_DEPTH_STENCIL_DESC(D3D11_DEFAULT);
+
+ HRESULT hr = mDevice->CreateDepthStencilState(
+ &desc, getter_AddRefs(mDepthStencilStates[MLGDepthTestMode::Write]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_WRITE_DEPTH_STATE",
+ "Could not create write depth stencil state (%x)", hr);
+ }
+
+ desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
+ hr = mDevice->CreateDepthStencilState(
+ &desc, getter_AddRefs(mDepthStencilStates[MLGDepthTestMode::ReadOnly]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_READ_DEPTH_STATE",
+ "Could not create read depth stencil state (%x)", hr);
+ }
+
+ desc.DepthEnable = FALSE;
+ hr = mDevice->CreateDepthStencilState(
+ &desc, getter_AddRefs(mDepthStencilStates[MLGDepthTestMode::Disabled]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_DISABLED_DEPTH_STATE",
+ "Could not create disabled depth stencil state (%x)", hr);
+ }
+
+ desc = CD3D11_DEPTH_STENCIL_DESC(D3D11_DEFAULT);
+ desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
+ hr = mDevice->CreateDepthStencilState(
+ &desc,
+ getter_AddRefs(mDepthStencilStates[MLGDepthTestMode::AlwaysWrite]));
+ if (FAILED(hr)) {
+ return Fail("FEATURE_FAILURE_WRITE_DEPTH_STATE",
+ "Could not create always-write depth stencil state (%x)", hr);
+ }
+
+ return true;
+}
+
+bool MLGDeviceD3D11::InitVertexShader(VertexShaderID aShaderID) {
+ const ShaderBytes* code = mLazyVertexShaders[aShaderID];
+ HRESULT hr =
+ mDevice->CreateVertexShader(code->mData, code->mLength, nullptr,
+ getter_AddRefs(mVertexShaders[aShaderID]));
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Could not create vertex shader "
+ << hexa(unsigned(aShaderID)) << ": " << hexa(hr);
+ return false;
+ }
+ return true;
+}
+
+bool MLGDeviceD3D11::InitInputLayout(D3D11_INPUT_ELEMENT_DESC* aDesc,
+ size_t aNumElements,
+ const ShaderBytes& aCode,
+ VertexShaderID aShaderID) {
+ HRESULT hr = mDevice->CreateInputLayout(
+ aDesc, aNumElements, aCode.mData, aCode.mLength,
+ getter_AddRefs(mInputLayouts[aShaderID]));
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Could not create input layout for shader "
+ << hexa(unsigned(aShaderID)) << ": " << hexa(hr);
+ return false;
+ }
+ return true;
+}
+
+TextureFactoryIdentifier MLGDeviceD3D11::GetTextureFactoryIdentifier(
+ widget::CompositorWidget* aWidget) const {
+ TextureFactoryIdentifier ident(GetLayersBackend(), XRE_GetProcessType(),
+ GetMaxTextureSize());
+ if (aWidget) {
+ ident.mUseCompositorWnd = !!aWidget->AsWindows()->GetCompositorHwnd();
+ }
+ if (mSyncObject) {
+ ident.mSyncHandle = mSyncObject->GetSyncHandle();
+ }
+
+ return ident;
+}
+
+inline uint32_t GetMaxTextureSizeForFeatureLevel1(
+ D3D_FEATURE_LEVEL aFeatureLevel) {
+ int32_t maxTextureSize;
+ switch (aFeatureLevel) {
+ case D3D_FEATURE_LEVEL_11_1:
+ case D3D_FEATURE_LEVEL_11_0:
+ maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ break;
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ maxTextureSize = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ break;
+ case D3D_FEATURE_LEVEL_9_3:
+ maxTextureSize = D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ break;
+ default:
+ maxTextureSize = D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ }
+ return maxTextureSize;
+}
+
+LayersBackend MLGDeviceD3D11::GetLayersBackend() const {
+ return LayersBackend::LAYERS_D3D11;
+}
+
+int32_t MLGDeviceD3D11::GetMaxTextureSize() const {
+ return GetMaxTextureSizeForFeatureLevel1(mDevice->GetFeatureLevel());
+}
+
+RefPtr<MLGSwapChain> MLGDeviceD3D11::CreateSwapChainForWidget(
+ widget::CompositorWidget* aWidget) {
+ return MLGSwapChainD3D11::Create(this, mDevice, aWidget);
+}
+
+RefPtr<DataTextureSource> MLGDeviceD3D11::CreateDataTextureSource(
+ TextureFlags aFlags) {
+ return new DataTextureSourceD3D11(mDevice, gfx::SurfaceFormat::UNKNOWN,
+ aFlags);
+}
+
+static inline D3D11_MAP ToD3D11Map(MLGMapType aType) {
+ switch (aType) {
+ case MLGMapType::READ:
+ return D3D11_MAP_READ;
+ case MLGMapType::READ_WRITE:
+ return D3D11_MAP_READ_WRITE;
+ case MLGMapType::WRITE:
+ return D3D11_MAP_WRITE;
+ case MLGMapType::WRITE_DISCARD:
+ return D3D11_MAP_WRITE_DISCARD;
+ }
+ return D3D11_MAP_WRITE;
+}
+
+bool MLGDeviceD3D11::Map(MLGResource* aResource, MLGMapType aType,
+ MLGMappedResource* aMap) {
+ ID3D11Resource* resource = aResource->AsResourceD3D11()->GetResource();
+ MOZ_ASSERT(resource);
+
+ D3D11_MAPPED_SUBRESOURCE map;
+ HRESULT hr = mCtx->Map(resource, 0, ToD3D11Map(aType), 0, &map);
+
+ if (FAILED(hr)) {
+ gfxWarning() << "Could not map MLG resource: " << hexa(hr);
+ return false;
+ }
+
+ aMap->mData = reinterpret_cast<uint8_t*>(map.pData);
+ aMap->mStride = map.RowPitch;
+ return true;
+}
+
+void MLGDeviceD3D11::Unmap(MLGResource* aResource) {
+ ID3D11Resource* resource = aResource->AsResourceD3D11()->GetResource();
+ mCtx->Unmap(resource, 0);
+}
+
+void MLGDeviceD3D11::UpdatePartialResource(MLGResource* aResource,
+ const gfx::IntRect* aRect,
+ void* aData, uint32_t aStride) {
+ D3D11_BOX box;
+ if (aRect) {
+ box = RectToBox(*aRect);
+ }
+
+ ID3D11Resource* resource = aResource->AsResourceD3D11()->GetResource();
+ mCtx->UpdateSubresource(resource, 0, aRect ? &box : nullptr, aData, aStride,
+ 0);
+}
+
+void MLGDeviceD3D11::SetRenderTarget(MLGRenderTarget* aRT) {
+ ID3D11RenderTargetView* rtv = nullptr;
+ ID3D11DepthStencilView* dsv = nullptr;
+
+ if (aRT) {
+ MLGRenderTargetD3D11* rt = aRT->AsD3D11();
+ rtv = rt->GetRenderTargetView();
+ dsv = rt->GetDSV();
+ }
+
+ mCtx->OMSetRenderTargets(1, &rtv, dsv);
+ mCurrentRT = aRT;
+}
+
+MLGRenderTarget* MLGDeviceD3D11::GetRenderTarget() { return mCurrentRT; }
+
+void MLGDeviceD3D11::SetViewport(const gfx::IntRect& aViewport) {
+ D3D11_VIEWPORT vp;
+ vp.MaxDepth = 1.0f;
+ vp.MinDepth = 0.0f;
+ vp.TopLeftX = aViewport.X();
+ vp.TopLeftY = aViewport.Y();
+ vp.Width = aViewport.Width();
+ vp.Height = aViewport.Height();
+ mCtx->RSSetViewports(1, &vp);
+}
+
+static inline D3D11_RECT ToD3D11Rect(const gfx::IntRect& aRect) {
+ D3D11_RECT rect;
+ rect.left = aRect.X();
+ rect.top = aRect.Y();
+ rect.right = aRect.XMost();
+ rect.bottom = aRect.YMost();
+ return rect;
+}
+
+void MLGDeviceD3D11::SetScissorRect(const Maybe<gfx::IntRect>& aScissorRect) {
+ if (!aScissorRect) {
+ if (mScissored) {
+ mCtx->RSSetState(mRasterizerStateNoScissor);
+ mScissored = false;
+ }
+ return;
+ }
+ D3D11_RECT rect = ToD3D11Rect(aScissorRect.value());
+ mCtx->RSSetScissorRects(1, &rect);
+ if (!mScissored) {
+ mScissored = true;
+ mCtx->RSSetState(mRasterizerStateScissor);
+ }
+}
+
+void MLGDeviceD3D11::SetVertexShader(VertexShaderID aShader) {
+ if (!mVertexShaders[aShader]) {
+ InitVertexShader(aShader);
+ MOZ_ASSERT(mInputLayouts[aShader]);
+ }
+ SetVertexShader(mVertexShaders[aShader]);
+ SetInputLayout(mInputLayouts[aShader]);
+}
+
+void MLGDeviceD3D11::SetInputLayout(ID3D11InputLayout* aLayout) {
+ if (mCurrentInputLayout == aLayout) {
+ return;
+ }
+ mCtx->IASetInputLayout(aLayout);
+ mCurrentInputLayout = aLayout;
+}
+
+void MLGDeviceD3D11::SetVertexShader(ID3D11VertexShader* aShader) {
+ if (mCurrentVertexShader == aShader) {
+ return;
+ }
+ mCtx->VSSetShader(aShader, nullptr, 0);
+ mCurrentVertexShader = aShader;
+}
+
+void MLGDeviceD3D11::SetPixelShader(PixelShaderID aShader) {
+ if (!mPixelShaders[aShader]) {
+ InitPixelShader(aShader);
+ }
+ if (mCurrentPixelShader != mPixelShaders[aShader]) {
+ mCtx->PSSetShader(mPixelShaders[aShader], nullptr, 0);
+ mCurrentPixelShader = mPixelShaders[aShader];
+ }
+}
+
+void MLGDeviceD3D11::SetSamplerMode(uint32_t aIndex, SamplerMode aMode) {
+ ID3D11SamplerState* sampler = mSamplerStates[aMode];
+ mCtx->PSSetSamplers(aIndex, 1, &sampler);
+}
+
+void MLGDeviceD3D11::SetBlendState(MLGBlendState aState) {
+ if (mCurrentBlendState != mBlendStates[aState]) {
+ FLOAT blendFactor[4] = {0, 0, 0, 0};
+ mCtx->OMSetBlendState(mBlendStates[aState], blendFactor, 0xFFFFFFFF);
+ mCurrentBlendState = mBlendStates[aState];
+ }
+}
+
+void MLGDeviceD3D11::SetVertexBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
+ uint32_t aStride, uint32_t aOffset) {
+ ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
+ mCtx->IASetVertexBuffers(aSlot, 1, &buffer, &aStride, &aOffset);
+}
+
+void MLGDeviceD3D11::SetVSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer) {
+ MOZ_ASSERT(aSlot < kMaxVertexShaderConstantBuffers);
+
+ ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
+ mCtx->VSSetConstantBuffers(aSlot, 1, &buffer);
+}
+
+void MLGDeviceD3D11::SetPSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer) {
+ MOZ_ASSERT(aSlot < kMaxPixelShaderConstantBuffers);
+
+ ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
+ mCtx->PSSetConstantBuffers(aSlot, 1, &buffer);
+}
+
+void MLGDeviceD3D11::SetVSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
+ uint32_t aFirstConstant,
+ uint32_t aNumConstants) {
+ MOZ_ASSERT(aSlot < kMaxVertexShaderConstantBuffers);
+ MOZ_ASSERT(mCanUseConstantBufferOffsetBinding);
+ MOZ_ASSERT(mCtx1);
+ MOZ_ASSERT(aFirstConstant % 16 == 0);
+
+ ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
+ mCtx1->VSSetConstantBuffers1(aSlot, 1, &buffer, &aFirstConstant,
+ &aNumConstants);
+}
+
+void MLGDeviceD3D11::SetPSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
+ uint32_t aFirstConstant,
+ uint32_t aNumConstants) {
+ MOZ_ASSERT(aSlot < kMaxPixelShaderConstantBuffers);
+ MOZ_ASSERT(mCanUseConstantBufferOffsetBinding);
+ MOZ_ASSERT(mCtx1);
+ MOZ_ASSERT(aFirstConstant % 16 == 0);
+
+ ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
+ mCtx1->PSSetConstantBuffers1(aSlot, 1, &buffer, &aFirstConstant,
+ &aNumConstants);
+}
+
+void MLGDeviceD3D11::SetPrimitiveTopology(MLGPrimitiveTopology aTopology) {
+ D3D11_PRIMITIVE_TOPOLOGY topology;
+ switch (aTopology) {
+ case MLGPrimitiveTopology::TriangleStrip:
+ topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
+ break;
+ case MLGPrimitiveTopology::TriangleList:
+ topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+ break;
+ case MLGPrimitiveTopology::UnitQuad:
+ SetVertexBuffer(0, mUnitQuadVB, sizeof(float) * 2, 0);
+ topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
+ break;
+ case MLGPrimitiveTopology::UnitTriangle:
+ SetVertexBuffer(0, mUnitTriangleVB, sizeof(float) * 3, 0);
+ topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown topology");
+ topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
+ break;
+ }
+
+ mCtx->IASetPrimitiveTopology(topology);
+}
+
+RefPtr<MLGBuffer> MLGDeviceD3D11::CreateBuffer(MLGBufferType aType,
+ uint32_t aSize, MLGUsage aUsage,
+ const void* aInitialData) {
+ return MLGBufferD3D11::Create(mDevice, aType, aSize, aUsage, aInitialData);
+}
+
+RefPtr<MLGRenderTarget> MLGDeviceD3D11::CreateRenderTarget(
+ const gfx::IntSize& aSize, MLGRenderTargetFlags aFlags) {
+ RefPtr<MLGRenderTargetD3D11> rt = new MLGRenderTargetD3D11(aSize, aFlags);
+ if (!rt->Initialize(mDevice)) {
+ return nullptr;
+ }
+ return rt;
+}
+
+void MLGDeviceD3D11::Clear(MLGRenderTarget* aRT,
+ const gfx::DeviceColor& aColor) {
+ MLGRenderTargetD3D11* rt = aRT->AsD3D11();
+ FLOAT rgba[4] = {aColor.r, aColor.g, aColor.b, aColor.a};
+ mCtx->ClearRenderTargetView(rt->GetRenderTargetView(), rgba);
+ if (ID3D11DepthStencilView* dsv = rt->GetDSV()) {
+ mCtx->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH, 1.0, 0);
+ }
+}
+
+void MLGDeviceD3D11::ClearDepthBuffer(MLGRenderTarget* aRT) {
+ MLGRenderTargetD3D11* rt = aRT->AsD3D11();
+ if (ID3D11DepthStencilView* dsv = rt->GetDSV()) {
+ mCtx->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH, 1.0, 0);
+ }
+}
+
+void MLGDeviceD3D11::ClearView(MLGRenderTarget* aRT, const DeviceColor& aColor,
+ const IntRect* aRects, size_t aNumRects) {
+ MOZ_ASSERT(mCanUseClearView);
+ MOZ_ASSERT(mCtx1);
+
+ MLGRenderTargetD3D11* rt = aRT->AsD3D11();
+ FLOAT rgba[4] = {aColor.r, aColor.g, aColor.b, aColor.a};
+
+ StackArray<D3D11_RECT, 8> rects(aNumRects);
+ for (size_t i = 0; i < aNumRects; i++) {
+ rects[i] = ToD3D11Rect(aRects[i]);
+ }
+
+ // Batch ClearView calls since too many will crash NVIDIA drivers.
+ size_t remaining = aNumRects;
+ size_t cursor = 0;
+ while (remaining > 0) {
+ size_t amount = std::min(remaining, kMaxClearViewRects);
+ mCtx1->ClearView(rt->GetRenderTargetView(), rgba, rects.data() + cursor,
+ amount);
+
+ remaining -= amount;
+ cursor += amount;
+ }
+}
+
+void MLGDeviceD3D11::Draw(uint32_t aVertexCount, uint32_t aOffset) {
+ mCtx->Draw(aVertexCount, aOffset);
+}
+
+void MLGDeviceD3D11::DrawInstanced(uint32_t aVertexCountPerInstance,
+ uint32_t aInstanceCount,
+ uint32_t aVertexOffset,
+ uint32_t aInstanceOffset) {
+ mCtx->DrawInstanced(aVertexCountPerInstance, aInstanceCount, aVertexOffset,
+ aInstanceOffset);
+}
+
+void MLGDeviceD3D11::SetPSTextures(uint32_t aSlot, uint32_t aNumTextures,
+ TextureSource* const* aTextures) {
+ // TextureSource guarantees that the ID3D11ShaderResourceView will be cached,
+ // so we don't hold a RefPtr here.
+ StackArray<ID3D11ShaderResourceView*, 3> views(aNumTextures);
+
+ for (size_t i = 0; i < aNumTextures; i++) {
+ views[i] = ResolveTextureSourceForShader(aTextures[i]);
+ }
+
+ mCtx->PSSetShaderResources(aSlot, aNumTextures, views.data());
+}
+
+ID3D11ShaderResourceView* MLGDeviceD3D11::ResolveTextureSourceForShader(
+ TextureSource* aTexture) {
+ if (!aTexture) {
+ return nullptr;
+ }
+
+ if (TextureSourceD3D11* source = aTexture->AsSourceD3D11()) {
+ ID3D11Texture2D* texture = source->GetD3D11Texture();
+ if (!texture) {
+ gfxWarning() << "No D3D11 texture present in SetPSTextures";
+ return nullptr;
+ }
+
+ MaybeLockTexture(texture);
+ return source->GetShaderResourceView();
+ }
+
+ gfxWarning() << "Unknown texture type in SetPSTextures";
+ return nullptr;
+}
+
+void MLGDeviceD3D11::SetPSTexture(uint32_t aSlot, MLGTexture* aTexture) {
+ RefPtr<ID3D11ShaderResourceView> view;
+ if (aTexture) {
+ MLGTextureD3D11* texture = aTexture->AsD3D11();
+ view = texture->GetShaderResourceView();
+ }
+
+ ID3D11ShaderResourceView* viewPtr = view.get();
+ mCtx->PSSetShaderResources(aSlot, 1, &viewPtr);
+}
+
+void MLGDeviceD3D11::MaybeLockTexture(ID3D11Texture2D* aTexture) {
+ RefPtr<IDXGIKeyedMutex> mutex;
+ HRESULT hr = aTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
+ (void**)getter_AddRefs(mutex));
+ if (FAILED(hr) || !mutex) {
+ return;
+ }
+
+ hr = mutex->AcquireSync(0, 10000);
+
+ if (hr == WAIT_TIMEOUT) {
+ gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout";
+ mLockAttemptedTextures.PutEntry(mutex);
+ } else if (hr == WAIT_ABANDONED) {
+ gfxCriticalNote << "GFX: D3D11 lock mutex abandoned";
+ mLockAttemptedTextures.PutEntry(mutex);
+ } else if (FAILED(hr)) {
+ gfxCriticalNote << "D3D11 lock mutex failed: " << hexa(hr);
+ mLockAttemptedTextures.PutEntry(mutex);
+ } else {
+ mLockedTextures.PutEntry(mutex);
+ }
+}
+
+void MLGDeviceD3D11::SetPSTexturesNV12(uint32_t aSlot,
+ TextureSource* aTexture) {
+ MOZ_ASSERT(aTexture->GetFormat() == SurfaceFormat::NV12 ||
+ aTexture->GetFormat() == SurfaceFormat::P010 ||
+ aTexture->GetFormat() == SurfaceFormat::P016);
+
+ TextureSourceD3D11* source = aTexture->AsSourceD3D11();
+ if (!source) {
+ gfxWarning() << "Unknown texture type in SetPSCompoundTexture";
+ return;
+ }
+
+ ID3D11Texture2D* texture = source->GetD3D11Texture();
+ if (!texture) {
+ gfxWarning() << "TextureSourceD3D11 does not have an ID3D11Texture";
+ return;
+ }
+
+ MaybeLockTexture(texture);
+
+ const bool isNV12 = aTexture->GetFormat() == SurfaceFormat::NV12;
+
+ RefPtr<ID3D11ShaderResourceView> views[2];
+ D3D11_SHADER_RESOURCE_VIEW_DESC desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(
+ D3D11_SRV_DIMENSION_TEXTURE2D,
+ isNV12 ? DXGI_FORMAT_R8_UNORM : DXGI_FORMAT_R16_UNORM);
+
+ HRESULT hr = mDevice->CreateShaderResourceView(texture, &desc,
+ getter_AddRefs(views[0]));
+ if (FAILED(hr) || !views[0]) {
+ gfxWarning() << "Could not bind an SRV for Y plane of NV12 texture: "
+ << hexa(hr);
+ return;
+ }
+
+ desc.Format = isNV12 ? DXGI_FORMAT_R8G8_UNORM : DXGI_FORMAT_R16G16_UNORM;
+ hr = mDevice->CreateShaderResourceView(texture, &desc,
+ getter_AddRefs(views[1]));
+ if (FAILED(hr) || !views[1]) {
+ gfxWarning() << "Could not bind an SRV for CbCr plane of NV12 texture: "
+ << hexa(hr);
+ return;
+ }
+
+ ID3D11ShaderResourceView* bind[2] = {views[0], views[1]};
+ mCtx->PSSetShaderResources(aSlot, 2, bind);
+}
+
+bool MLGDeviceD3D11::InitSyncObject() {
+ MOZ_ASSERT(!mSyncObject);
+ MOZ_ASSERT(mDevice);
+
+ mSyncObject = SyncObjectHost::CreateSyncObjectHost(mDevice);
+ MOZ_ASSERT(mSyncObject);
+
+ return mSyncObject->Init();
+}
+
+void MLGDeviceD3D11::StartDiagnostics(uint32_t aInvalidPixels) {
+ mDiagnostics->Start(aInvalidPixels);
+}
+
+void MLGDeviceD3D11::EndDiagnostics() { mDiagnostics->End(); }
+
+void MLGDeviceD3D11::GetDiagnostics(GPUStats* aStats) {
+ mDiagnostics->Query(aStats);
+}
+
+bool MLGDeviceD3D11::Synchronize() {
+ MOZ_ASSERT(mSyncObject);
+
+ if (mSyncObject) {
+ if (!mSyncObject->Synchronize()) {
+ // It's timeout or other error. Handle the device-reset here.
+ HandleDeviceReset("SyncObject");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void MLGDeviceD3D11::UnlockAllTextures() {
+ for (auto iter = mLockedTextures.Iter(); !iter.Done(); iter.Next()) {
+ RefPtr<IDXGIKeyedMutex> mutex = iter.Get()->GetKey();
+ mutex->ReleaseSync(0);
+ }
+ mLockedTextures.Clear();
+ mLockAttemptedTextures.Clear();
+}
+
+void MLGDeviceD3D11::SetDepthTestMode(MLGDepthTestMode aMode) {
+ mCtx->OMSetDepthStencilState(mDepthStencilStates[aMode], 0xffffffff);
+}
+
+void MLGDeviceD3D11::InsertPresentWaitQuery() {
+ CD3D11_QUERY_DESC desc(D3D11_QUERY_EVENT);
+ HRESULT hr =
+ mDevice->CreateQuery(&desc, getter_AddRefs(mNextWaitForPresentQuery));
+ if (FAILED(hr) || !mNextWaitForPresentQuery) {
+ gfxWarning() << "Could not create D3D11_QUERY_EVENT: " << hexa(hr);
+ return;
+ }
+
+ mCtx->End(mNextWaitForPresentQuery);
+}
+
+void MLGDeviceD3D11::WaitForPreviousPresentQuery() {
+ if (mWaitForPresentQuery) {
+ BOOL result;
+ WaitForFrameGPUQuery(mDevice, mCtx, mWaitForPresentQuery, &result);
+ }
+ mWaitForPresentQuery = mNextWaitForPresentQuery.forget();
+}
+
+void MLGDeviceD3D11::Flush() { mCtx->Flush(); }
+
+void MLGDeviceD3D11::EndFrame() {
+ // On our Windows 8 x64 machines, we have observed a driver bug related to
+ // XXSetConstantBuffers1. It appears binding the same buffer to multiple
+ // slots, and potentially leaving slots bound for many frames (as can
+ // happen if we bind a high slot, like for blending), can consistently
+ // cause shaders to read wrong values much later. It is possible there is
+ // a driver bug related to aliasing and partial binding.
+ //
+ // Configuration: GeForce GT 610 (0x104a), Driver 9.18.13.3523, 3-4-2014,
+ // on Windows 8 x64.
+ //
+ // To alleviate this we unbind all buffers at the end of the frame.
+ static ID3D11Buffer* nullBuffers[6] = {
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ };
+ MOZ_ASSERT(MOZ_ARRAY_LENGTH(nullBuffers) >= kMaxVertexShaderConstantBuffers);
+ MOZ_ASSERT(MOZ_ARRAY_LENGTH(nullBuffers) >= kMaxPixelShaderConstantBuffers);
+
+ mCtx->VSSetConstantBuffers(0, kMaxVertexShaderConstantBuffers, nullBuffers);
+ mCtx->VSSetConstantBuffers(0, kMaxPixelShaderConstantBuffers, nullBuffers);
+
+ MLGDevice::EndFrame();
+}
+
+void MLGDeviceD3D11::HandleDeviceReset(const char* aWhere) {
+ if (!IsValid()) {
+ return;
+ }
+
+ Fail("FEATURE_FAILURE_DEVICE_RESET"_ns, nullptr);
+
+ gfxCriticalNote << "GFX: D3D11 detected a device reset in " << aWhere;
+ if (XRE_IsGPUProcess()) {
+ GPUParent::GetSingleton()->NotifyDeviceReset();
+ }
+
+ UnmapSharedBuffers();
+ mIsValid = false;
+}
+
+RefPtr<MLGTexture> MLGDeviceD3D11::CreateTexture(const gfx::IntSize& aSize,
+ gfx::SurfaceFormat aFormat,
+ MLGUsage aUsage,
+ MLGTextureFlags aFlags) {
+ return MLGTextureD3D11::Create(mDevice, aSize, aFormat, aUsage, aFlags);
+}
+
+RefPtr<MLGTexture> MLGDeviceD3D11::CreateTexture(TextureSource* aSource) {
+ TextureSourceD3D11* source = aSource->AsSourceD3D11();
+ if (!source) {
+ gfxWarning() << "Attempted to wrap a non-D3D11 texture";
+ return nullptr;
+ }
+ if (!source->GetD3D11Texture()) {
+ return nullptr;
+ }
+ return new MLGTextureD3D11(source->GetD3D11Texture());
+}
+
+void MLGDeviceD3D11::CopyTexture(MLGTexture* aDest,
+ const gfx::IntPoint& aTarget,
+ MLGTexture* aSource,
+ const gfx::IntRect& aRect) {
+ MLGTextureD3D11* dest = aDest->AsD3D11();
+ MLGTextureD3D11* source = aSource->AsD3D11();
+
+ // We check both the source and destination copy regions, because
+ // CopySubresourceRegion is documented as causing a device reset if
+ // the operation is out-of-bounds. And it's not lying.
+ IntRect sourceBounds(IntPoint(0, 0), aSource->GetSize());
+ if (!sourceBounds.Contains(aRect)) {
+ gfxWarning() << "Attempt to read out-of-bounds in CopySubresourceRegion: "
+ << sourceBounds << ", " << aRect;
+ return;
+ }
+
+ IntRect destBounds(IntPoint(0, 0), aDest->GetSize());
+ if (!destBounds.Contains(IntRect(aTarget, aRect.Size()))) {
+ gfxWarning() << "Attempt to write out-of-bounds in CopySubresourceRegion: "
+ << destBounds << ", " << aTarget << ", " << aRect.Size();
+ return;
+ }
+
+ D3D11_BOX box = RectToBox(aRect);
+ mCtx->CopySubresourceRegion(dest->GetTexture(), 0, aTarget.x, aTarget.y, 0,
+ source->GetTexture(), 0, &box);
+}
+
+bool MLGDeviceD3D11::VerifyConstantBufferOffsetting() {
+ RefPtr<ID3D11VertexShader> vs;
+ HRESULT hr = mDevice->CreateVertexShader(sTestConstantBuffersVS.mData,
+ sTestConstantBuffersVS.mLength,
+ nullptr, getter_AddRefs(vs));
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Failed creating vertex shader for buffer test: "
+ << hexa(hr);
+ return false;
+ }
+
+ D3D11_INPUT_ELEMENT_DESC inputDesc[] = {{"POSITION", 0,
+ DXGI_FORMAT_R32G32_FLOAT, 0, 0,
+ D3D11_INPUT_PER_VERTEX_DATA, 0}};
+
+ RefPtr<ID3D11InputLayout> layout;
+ hr = mDevice->CreateInputLayout(
+ inputDesc, sizeof(inputDesc) / sizeof(inputDesc[0]),
+ sTestConstantBuffersVS.mData, sTestConstantBuffersVS.mLength,
+ getter_AddRefs(layout));
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Failed creating input layout for buffer test: "
+ << hexa(hr);
+ return false;
+ }
+
+ RefPtr<MLGRenderTarget> rt =
+ CreateRenderTarget(IntSize(2, 2), MLGRenderTargetFlags::Default);
+ if (!rt) {
+ return false;
+ }
+
+ static const size_t kConstantSize = 4 * sizeof(float);
+ static const size_t kMinConstants = 16;
+ static const size_t kNumBindings = 3;
+
+ RefPtr<MLGBuffer> buffer = CreateBuffer(
+ MLGBufferType::Constant, kConstantSize * kMinConstants * kNumBindings,
+ MLGUsage::Dynamic, nullptr);
+ if (!buffer) {
+ return false;
+ }
+
+ // Populate the buffer. The shader will pick R from buffer 1, G from buffer
+ // 2, and B from buffer 3.
+ {
+ MLGMappedResource map;
+ if (!Map(buffer, MLGMapType::WRITE_DISCARD, &map)) {
+ return false;
+ }
+
+ *reinterpret_cast<DeviceColor*>(map.mData) =
+ DeviceColor(1.0f, 0.2f, 0.3f, 1.0f);
+ *reinterpret_cast<DeviceColor*>(map.mData + kConstantSize * kMinConstants) =
+ DeviceColor(0.4f, 0.0f, 0.5f, 1.0f);
+ *reinterpret_cast<DeviceColor*>(map.mData +
+ (kConstantSize * kMinConstants) * 2) =
+ DeviceColor(0.6f, 0.7f, 1.0f, 1.0f);
+
+ Unmap(buffer);
+ }
+
+ Clear(rt, DeviceColor(0.0f, 0.0f, 0.0f, 1.0f));
+ SetRenderTarget(rt);
+ SetViewport(IntRect(0, 0, 2, 2));
+ SetScissorRect(Nothing());
+ SetBlendState(MLGBlendState::Over);
+
+ SetTopology(MLGPrimitiveTopology::UnitQuad);
+ SetInputLayout(layout);
+ SetVertexShader(vs);
+ SetPixelShader(PixelShaderID::ColoredQuad);
+
+ ID3D11Buffer* buffers[3] = {buffer->AsD3D11()->GetBuffer(),
+ buffer->AsD3D11()->GetBuffer(),
+ buffer->AsD3D11()->GetBuffer()};
+ UINT offsets[3] = {0 * kMinConstants, 1 * kMinConstants, 2 * kMinConstants};
+ UINT counts[3] = {kMinConstants, kMinConstants, kMinConstants};
+
+ mCtx1->VSSetConstantBuffers1(0, 3, buffers, offsets, counts);
+ mCtx->Draw(4, 0);
+
+ // Kill bindings to resources.
+ SetRenderTarget(nullptr);
+
+ ID3D11Buffer* nulls[3] = {nullptr, nullptr, nullptr};
+ mCtx->VSSetConstantBuffers(0, 3, nulls);
+
+ RefPtr<MLGTexture> copy =
+ CreateTexture(IntSize(2, 2), SurfaceFormat::B8G8R8A8, MLGUsage::Staging,
+ MLGTextureFlags::None);
+ if (!copy) {
+ return false;
+ }
+
+ CopyTexture(copy, IntPoint(0, 0), rt->GetTexture(), IntRect(0, 0, 2, 2));
+
+ uint8_t r, g, b, a;
+ {
+ MLGMappedResource map;
+ if (!Map(copy, MLGMapType::READ, &map)) {
+ return false;
+ }
+ r = map.mData[0];
+ g = map.mData[1];
+ b = map.mData[2];
+ a = map.mData[3];
+ Unmap(copy);
+ }
+
+ return r == 255 && g == 0 && b == 255 && a == 255;
+}
+
+static D3D11_BOX RectToBox(const gfx::IntRect& aRect) {
+ D3D11_BOX box;
+ box.front = 0;
+ box.back = 1;
+ box.left = aRect.X();
+ box.top = aRect.Y();
+ box.right = aRect.XMost();
+ box.bottom = aRect.YMost();
+ return box;
+}
+
+} // namespace layers
+} // namespace mozilla