From 4144e3229a633d771ccbe8afc9a904b4e9a3ddfd Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 11 Dec 2017 13:03:07 +0100 Subject: [PATCH] [d3d11] Implemented blend state creation --- src/d3d11/d3d11_blend.cpp | 126 ++++++++++++++++++++++++++++++ src/d3d11/d3d11_blend.h | 57 ++++++++++++++ src/d3d11/d3d11_context.cpp | 7 +- src/d3d11/d3d11_device.cpp | 28 ++++++- src/d3d11/d3d11_device.h | 1 + src/d3d11/d3d11_state.cpp | 84 ++++++++++++++++++-- src/d3d11/d3d11_state.h | 5 ++ src/d3d11/meson.build | 1 + src/dxgi/dxgi_presenter.cpp | 1 + src/dxvk/dxvk_constant_state.h | 1 + src/dxvk/dxvk_context.cpp | 2 +- src/dxvk/dxvk_context_state.h | 1 - tests/dxvk/test_dxvk_triangle.cpp | 1 + 13 files changed, 302 insertions(+), 13 deletions(-) create mode 100644 src/d3d11/d3d11_blend.cpp create mode 100644 src/d3d11/d3d11_blend.h diff --git a/src/d3d11/d3d11_blend.cpp b/src/d3d11/d3d11_blend.cpp new file mode 100644 index 00000000..a7d6dd65 --- /dev/null +++ b/src/d3d11/d3d11_blend.cpp @@ -0,0 +1,126 @@ +#include "d3d11_blend.h" +#include "d3d11_device.h" + +namespace dxvk { + + D3D11BlendState::D3D11BlendState( + D3D11Device* device, + const D3D11_BLEND_DESC& desc) + : m_device(device), m_desc(desc) { + // If Independent Blend is disabled, we must ignore the + // blend modes for render target 1 to 7. In Vulkan, all + // blend modes need to be identical in that case. + for (uint32_t i = 0; i < m_blendModes.size(); i++) { + m_blendModes.at(i) = DecodeBlendMode( + desc.IndependentBlendEnable + ? desc.RenderTarget[i] + : desc.RenderTarget[0]); + } + + // Multisample state is part of the blend state in D3D11 + m_msState.sampleMask = 0; // Set during bind + m_msState.enableAlphaToCoverage = desc.AlphaToCoverageEnable; + m_msState.enableAlphaToOne = VK_FALSE; + m_msState.enableSampleShading = VK_FALSE; + m_msState.minSampleShading = 0.0f; + } + + + D3D11BlendState::~D3D11BlendState() { + + } + + + HRESULT D3D11BlendState::QueryInterface(REFIID riid, void** ppvObject) { + COM_QUERY_IFACE(riid, ppvObject, IUnknown); + COM_QUERY_IFACE(riid, ppvObject, ID3D11DeviceChild); + COM_QUERY_IFACE(riid, ppvObject, ID3D11BlendState); + + Logger::warn("D3D11BlendState::QueryInterface: Unknown interface query"); + return E_NOINTERFACE; + } + + + void D3D11BlendState::GetDevice(ID3D11Device** ppDevice) { + *ppDevice = ref(m_device); + } + + + void D3D11BlendState::GetDesc(D3D11_BLEND_DESC* pDesc) { + *pDesc = m_desc; + } + + + void D3D11BlendState::BindToContext( + const Rc& ctx, + uint32_t sampleMask) const { + // We handled Independent Blend during object creation + // already, so if it is disabled, all elements in the + // blend mode array will be identical + for (uint32_t i = 0; i < m_blendModes.size(); i++) + ctx->setBlendMode(i, m_blendModes.at(i)); + + // The sample mask is dynamic state in D3D11 + DxvkMultisampleState msState = m_msState; + msState.sampleMask = sampleMask; + ctx->setMultisampleState(msState); + } + + + DxvkBlendMode D3D11BlendState::DecodeBlendMode( + const D3D11_RENDER_TARGET_BLEND_DESC& blendDesc) { + DxvkBlendMode mode; + mode.enableBlending = blendDesc.BlendEnable; + mode.colorSrcFactor = DecodeBlendFactor(blendDesc.SrcBlend, false); + mode.colorDstFactor = DecodeBlendFactor(blendDesc.DestBlend, false); + mode.colorBlendOp = DecodeBlendOp(blendDesc.BlendOp); + mode.alphaSrcFactor = DecodeBlendFactor(blendDesc.SrcBlendAlpha, true); + mode.alphaDstFactor = DecodeBlendFactor(blendDesc.DestBlendAlpha, true); + mode.alphaBlendOp = DecodeBlendOp(blendDesc.BlendOpAlpha); + // TODO find out if D3D11 wants us to apply the write mask if blending + // is disabled as well. This is standard behaviour in Vulkan. + mode.writeMask = blendDesc.RenderTargetWriteMask; + return mode; + } + + + VkBlendFactor D3D11BlendState::DecodeBlendFactor(D3D11_BLEND blendFactor, bool isAlpha) { + switch (blendFactor) { + case D3D11_BLEND_ZERO: return VK_BLEND_FACTOR_ZERO; + case D3D11_BLEND_ONE: return VK_BLEND_FACTOR_ONE; + case D3D11_BLEND_SRC_COLOR: return VK_BLEND_FACTOR_SRC_COLOR; + case D3D11_BLEND_INV_SRC_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + case D3D11_BLEND_SRC_ALPHA: return VK_BLEND_FACTOR_SRC_ALPHA; + case D3D11_BLEND_INV_SRC_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + case D3D11_BLEND_DEST_ALPHA: return VK_BLEND_FACTOR_DST_ALPHA; + case D3D11_BLEND_INV_DEST_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + case D3D11_BLEND_DEST_COLOR: return VK_BLEND_FACTOR_DST_COLOR; + case D3D11_BLEND_INV_DEST_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + case D3D11_BLEND_SRC_ALPHA_SAT: return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; + case D3D11_BLEND_BLEND_FACTOR: return isAlpha ? VK_BLEND_FACTOR_CONSTANT_ALPHA : VK_BLEND_FACTOR_CONSTANT_COLOR; + case D3D11_BLEND_INV_BLEND_FACTOR: return isAlpha ? VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA : VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; + case D3D11_BLEND_SRC1_COLOR: return VK_BLEND_FACTOR_SRC1_COLOR; + case D3D11_BLEND_INV_SRC1_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; + case D3D11_BLEND_SRC1_ALPHA: return VK_BLEND_FACTOR_SRC1_ALPHA; + case D3D11_BLEND_INV_SRC1_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; + } + + Logger::err(str::format("D3D11: Invalid blend factor: ", blendFactor)); + return VK_BLEND_FACTOR_ZERO; + } + + + VkBlendOp D3D11BlendState::DecodeBlendOp(D3D11_BLEND_OP blendOp) { + switch (blendOp) { + case D3D11_BLEND_OP_ADD: return VK_BLEND_OP_ADD; + case D3D11_BLEND_OP_SUBTRACT: return VK_BLEND_OP_SUBTRACT; + case D3D11_BLEND_OP_REV_SUBTRACT: return VK_BLEND_OP_REVERSE_SUBTRACT; + case D3D11_BLEND_OP_MIN: return VK_BLEND_OP_MIN; + case D3D11_BLEND_OP_MAX: return VK_BLEND_OP_MAX; + } + + Logger::err(str::format("D3D11: Invalid blend op: ", blendOp)); + return VK_BLEND_OP_ADD; + } + +} diff --git a/src/d3d11/d3d11_blend.h b/src/d3d11/d3d11_blend.h new file mode 100644 index 00000000..b8f418c1 --- /dev/null +++ b/src/d3d11/d3d11_blend.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include "d3d11_device_child.h" +#include "d3d11_util.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11BlendState : public D3D11DeviceChild { + + public: + + using DescType = D3D11_BLEND_DESC; + + D3D11BlendState( + D3D11Device* device, + const D3D11_BLEND_DESC& desc); + ~D3D11BlendState(); + + HRESULT QueryInterface( + REFIID riid, + void** ppvObject) final; + + void GetDevice( + ID3D11Device **ppDevice) final; + + void GetDesc( + D3D11_BLEND_DESC* pDesc) final; + + void BindToContext( + const Rc& ctx, + uint32_t sampleMask) const; + + private: + + D3D11Device* const m_device; + D3D11_BLEND_DESC m_desc; + + std::array m_blendModes; + DxvkMultisampleState m_msState; + + static DxvkBlendMode DecodeBlendMode( + const D3D11_RENDER_TARGET_BLEND_DESC& blendDesc); + + static VkBlendFactor DecodeBlendFactor( + D3D11_BLEND blendFactor, + bool isAlpha); + + static VkBlendOp DecodeBlendOp( + D3D11_BLEND_OP blendOp); + + }; + +} diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index afdba50c..5e915e6f 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -1559,6 +1559,7 @@ namespace dxvk { void D3D11DeviceContext::SetDefaultBlendState() { DxvkMultisampleState msState; + msState.sampleMask = 0xffffffff; msState.enableAlphaToCoverage = VK_FALSE; msState.enableAlphaToOne = VK_FALSE; msState.enableSampleShading = VK_FALSE; @@ -1579,9 +1580,9 @@ namespace dxvk { blendMode.alphaDstFactor = VK_BLEND_FACTOR_ZERO; blendMode.alphaBlendOp = VK_BLEND_OP_ADD; blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT - | VK_COLOR_COMPONENT_G_BIT - | VK_COLOR_COMPONENT_B_BIT - | VK_COLOR_COMPONENT_A_BIT; + | VK_COLOR_COMPONENT_G_BIT + | VK_COLOR_COMPONENT_B_BIT + | VK_COLOR_COMPONENT_A_BIT; for (uint32_t i = 0; i < DxvkLimits::MaxNumRenderTargets; i++) m_context->setBlendMode(i, blendMode); diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index c4fe30bf..57fcf69b 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -802,8 +802,32 @@ namespace dxvk { HRESULT D3D11Device::CreateBlendState( const D3D11_BLEND_DESC* pBlendStateDesc, ID3D11BlendState** ppBlendState) { - Logger::err("D3D11Device::CreateBlendState: Not implemented"); - return E_NOTIMPL; + D3D11_BLEND_DESC desc; + + if (pBlendStateDesc != nullptr) { + desc = *pBlendStateDesc; + } else { + desc.AlphaToCoverageEnable = FALSE; + desc.IndependentBlendEnable = FALSE; + + // 1-7 must be ignored if IndependentBlendEnable is disabled so + // technically this is not needed, but since this structure is + // going to be copied around we'll initialize it nonetheless + for (uint32_t i = 0; i < 8; i++) { + desc.RenderTarget[i].BlendEnable = FALSE; + desc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; + desc.RenderTarget[i].DestBlend = D3D11_BLEND_ZERO; + desc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + desc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + desc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ZERO; + desc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + desc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + } + } + + if (ppBlendState != nullptr) + *ppBlendState = m_bsStateObjects.Create(this, desc); + return S_OK; } diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 39d65baf..c72de8d5 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -248,6 +248,7 @@ namespace dxvk { std::mutex m_resourceInitMutex; Rc m_resourceInitContext; + D3D11StateObjectSet m_bsStateObjects; D3D11StateObjectSet m_dsStateObjects; D3D11StateObjectSet m_rsStateObjects; diff --git a/src/d3d11/d3d11_state.cpp b/src/d3d11/d3d11_state.cpp index b2d6ea21..4d5f47b2 100644 --- a/src/d3d11/d3d11_state.cpp +++ b/src/d3d11/d3d11_state.cpp @@ -2,7 +2,25 @@ namespace dxvk { - size_t D3D11StateDescHash::operator () (const D3D11_DEPTH_STENCILOP_DESC& desc) const { + size_t D3D11StateDescHash::operator () ( + const D3D11_BLEND_DESC& desc) const { + DxvkHashState hash; + hash.add(desc.AlphaToCoverageEnable); + hash.add(desc.IndependentBlendEnable); + + // Render targets 1 to 7 are ignored and may contain + // undefined data if independent blend is disabled + const uint32_t usedRenderTargets = desc.IndependentBlendEnable ? 8 : 1; + + for (uint32_t i = 0; i < usedRenderTargets; i++) + hash.add(this->operator () (desc.RenderTarget[i])); + + return hash; + } + + + size_t D3D11StateDescHash::operator () ( + const D3D11_DEPTH_STENCILOP_DESC& desc) const { DxvkHashState hash; hash.add(desc.StencilFunc); hash.add(desc.StencilDepthFailOp); @@ -12,7 +30,8 @@ namespace dxvk { } - size_t D3D11StateDescHash::operator () (const D3D11_DEPTH_STENCIL_DESC& desc) const { + size_t D3D11StateDescHash::operator () ( + const D3D11_DEPTH_STENCIL_DESC& desc) const { DxvkHashState hash; hash.add(desc.DepthEnable); hash.add(desc.DepthWriteMask); @@ -26,7 +45,8 @@ namespace dxvk { } - size_t D3D11StateDescHash::operator () (const D3D11_RASTERIZER_DESC& desc) const { + size_t D3D11StateDescHash::operator () ( + const D3D11_RASTERIZER_DESC& desc) const { DxvkHashState hash; hash.add(desc.FillMode); hash.add(desc.CullMode); @@ -42,7 +62,41 @@ namespace dxvk { } - bool D3D11StateDescEqual::operator () (const D3D11_DEPTH_STENCILOP_DESC& a, const D3D11_DEPTH_STENCILOP_DESC& b) const { + size_t D3D11StateDescHash::operator () ( + const D3D11_RENDER_TARGET_BLEND_DESC& desc) const { + DxvkHashState hash; + hash.add(desc.BlendEnable); + hash.add(desc.SrcBlend); + hash.add(desc.DestBlend); + hash.add(desc.BlendOp); + hash.add(desc.SrcBlendAlpha); + hash.add(desc.DestBlendAlpha); + hash.add(desc.BlendOpAlpha); + hash.add(desc.RenderTargetWriteMask); + return hash; + } + + + bool D3D11StateDescEqual::operator () ( + const D3D11_BLEND_DESC& a, + const D3D11_BLEND_DESC& b) const { + bool eq = a.AlphaToCoverageEnable == b.AlphaToCoverageEnable + && a.IndependentBlendEnable == b.IndependentBlendEnable; + + // Render targets 1 to 7 are ignored and may contain + // undefined data if independent blend is disabled + const uint32_t usedRenderTargets = a.IndependentBlendEnable ? 8 : 1; + + for (uint32_t i = 0; !eq && (i < usedRenderTargets); i++) + eq &= this->operator () (a.RenderTarget[i], b.RenderTarget[i]); + + return eq; + } + + + bool D3D11StateDescEqual::operator () ( + const D3D11_DEPTH_STENCILOP_DESC& a, + const D3D11_DEPTH_STENCILOP_DESC& b) const { return a.StencilFunc == b.StencilFunc && a.StencilDepthFailOp == b.StencilDepthFailOp && a.StencilPassOp == b.StencilPassOp @@ -50,7 +104,9 @@ namespace dxvk { } - bool D3D11StateDescEqual::operator () (const D3D11_DEPTH_STENCIL_DESC& a, const D3D11_DEPTH_STENCIL_DESC& b) const { + bool D3D11StateDescEqual::operator () ( + const D3D11_DEPTH_STENCIL_DESC& a, + const D3D11_DEPTH_STENCIL_DESC& b) const { return a.DepthEnable == b.DepthEnable && a.DepthWriteMask == b.DepthWriteMask && a.DepthFunc == b.DepthFunc @@ -62,7 +118,9 @@ namespace dxvk { } - bool D3D11StateDescEqual::operator () (const D3D11_RASTERIZER_DESC& a, const D3D11_RASTERIZER_DESC& b) const { + bool D3D11StateDescEqual::operator () ( + const D3D11_RASTERIZER_DESC& a, + const D3D11_RASTERIZER_DESC& b) const { return a.FillMode == b.FillMode && a.CullMode == b.CullMode && a.FrontCounterClockwise == b.FrontCounterClockwise @@ -75,4 +133,18 @@ namespace dxvk { && a.AntialiasedLineEnable == b.AntialiasedLineEnable; } + + bool D3D11StateDescEqual::operator () ( + const D3D11_RENDER_TARGET_BLEND_DESC& a, + const D3D11_RENDER_TARGET_BLEND_DESC& b) const { + return a.BlendEnable == b.BlendEnable + && a.SrcBlend == b.SrcBlend + && a.DestBlend == b.DestBlend + && a.BlendOp == b.BlendOp + && a.SrcBlendAlpha == b.SrcBlendAlpha + && a.DestBlendAlpha == b.DestBlendAlpha + && a.BlendOpAlpha == b.BlendOpAlpha + && a.RenderTargetWriteMask == b.RenderTargetWriteMask; + } + } \ No newline at end of file diff --git a/src/d3d11/d3d11_state.h b/src/d3d11/d3d11_state.h index 3d9b8b34..396302ce 100644 --- a/src/d3d11/d3d11_state.h +++ b/src/d3d11/d3d11_state.h @@ -2,6 +2,7 @@ #include +#include "d3d11_blend.h" #include "d3d11_depth_stencil.h" #include "d3d11_rasterizer.h" @@ -10,16 +11,20 @@ namespace dxvk { class D3D11Device; struct D3D11StateDescHash { + size_t operator () (const D3D11_BLEND_DESC& desc) const; size_t operator () (const D3D11_DEPTH_STENCILOP_DESC& desc) const; size_t operator () (const D3D11_DEPTH_STENCIL_DESC& desc) const; size_t operator () (const D3D11_RASTERIZER_DESC& desc) const; + size_t operator () (const D3D11_RENDER_TARGET_BLEND_DESC& desc) const; }; struct D3D11StateDescEqual { + bool operator () (const D3D11_BLEND_DESC& a, const D3D11_BLEND_DESC& b) const; bool operator () (const D3D11_DEPTH_STENCILOP_DESC& a, const D3D11_DEPTH_STENCILOP_DESC& b) const; bool operator () (const D3D11_DEPTH_STENCIL_DESC& a, const D3D11_DEPTH_STENCIL_DESC& b) const; bool operator () (const D3D11_RASTERIZER_DESC& a, const D3D11_RASTERIZER_DESC& b) const; + bool operator () (const D3D11_RENDER_TARGET_BLEND_DESC& a, const D3D11_RENDER_TARGET_BLEND_DESC& b) const; }; diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index ba991110..1a6d7a78 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -1,4 +1,5 @@ d3d11_src = [ + 'd3d11_blend.cpp', 'd3d11_buffer.cpp', 'd3d11_context.cpp', 'd3d11_depth_stencil.cpp', diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index ba7295b4..0b569ae5 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -76,6 +76,7 @@ namespace dxvk { m_context->setRasterizerState(rsState); DxvkMultisampleState msState; + msState.sampleMask = 0xffffffff; msState.enableAlphaToCoverage = VK_FALSE; msState.enableAlphaToOne = VK_FALSE; msState.enableSampleShading = VK_FALSE; diff --git a/src/dxvk/dxvk_constant_state.h b/src/dxvk/dxvk_constant_state.h index 7e09949f..5f14c296 100644 --- a/src/dxvk/dxvk_constant_state.h +++ b/src/dxvk/dxvk_constant_state.h @@ -47,6 +47,7 @@ namespace dxvk { * aspects of multisampling. */ struct DxvkMultisampleState { + uint32_t sampleMask; VkBool32 enableAlphaToCoverage; VkBool32 enableAlphaToOne; VkBool32 enableSampleShading; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index b61ddec5..915baf04 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -702,7 +702,7 @@ namespace dxvk { // TODO implement multisampling support properly gpState.msSampleCount = VK_SAMPLE_COUNT_1_BIT; - gpState.msSampleMask = m_state.om.sampleMask; + gpState.msSampleMask = m_state.ms.sampleMask; gpState.msEnableAlphaToCoverage = m_state.ms.enableAlphaToCoverage; gpState.msEnableAlphaToOne = m_state.ms.enableAlphaToOne; gpState.msEnableSampleShading = m_state.ms.enableSampleShading; diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 7d1d319d..5dc9d48d 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -55,7 +55,6 @@ namespace dxvk { struct DxvkOutputMergerState { - uint32_t sampleMask = 0xFFFFFFFFu; Rc framebuffer; std::array blendModes; diff --git a/tests/dxvk/test_dxvk_triangle.cpp b/tests/dxvk/test_dxvk_triangle.cpp index 44ac11a5..cacbb03d 100644 --- a/tests/dxvk/test_dxvk_triangle.cpp +++ b/tests/dxvk/test_dxvk_triangle.cpp @@ -102,6 +102,7 @@ public: m_dxvkContext->setRasterizerState(rsState); DxvkMultisampleState msState; + msState.sampleMask = 0xffffffff; msState.enableAlphaToCoverage = VK_FALSE; msState.enableAlphaToOne = VK_FALSE; msState.enableSampleShading = VK_FALSE;