diff --git a/src/d3d11/d3d11_blend.cpp b/src/d3d11/d3d11_blend.cpp index 77f7f7f6f..c63576375 100644 --- a/src/d3d11/d3d11_blend.cpp +++ b/src/d3d11/d3d11_blend.cpp @@ -4,8 +4,8 @@ namespace dxvk { D3D11BlendState::D3D11BlendState( - D3D11Device* device, - const D3D11_BLEND_DESC& desc) + D3D11Device* device, + const D3D11_BLEND_DESC1& 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 @@ -24,10 +24,13 @@ namespace dxvk { m_msState.enableSampleShading = VK_FALSE; m_msState.minSampleShading = 0.0f; - // In 11_0, there is no logic op state. Later versions - // of D3D11 however put it into the blend state object. - m_loState.enableLogicOp = VK_FALSE; - m_loState.logicOp = VK_LOGIC_OP_NO_OP; + // Vulkan only supports a global logic op for the blend + // state, which might be problematic in some cases. + if (desc.IndependentBlendEnable && desc.RenderTarget[0].LogicOpEnable) + Logger::warn("D3D11: Per-target logic ops not supported"); + + m_loState.enableLogicOp = desc.RenderTarget[0].LogicOpEnable; + m_loState.logicOp = DecodeLogicOp(desc.RenderTarget[0].LogicOp); } @@ -40,6 +43,7 @@ namespace dxvk { COM_QUERY_IFACE(riid, ppvObject, IUnknown); COM_QUERY_IFACE(riid, ppvObject, ID3D11DeviceChild); COM_QUERY_IFACE(riid, ppvObject, ID3D11BlendState); + COM_QUERY_IFACE(riid, ppvObject, ID3D11BlendState1); Logger::warn("D3D11BlendState::QueryInterface: Unknown interface query"); Logger::warn(str::format(riid)); @@ -53,6 +57,23 @@ namespace dxvk { void STDMETHODCALLTYPE D3D11BlendState::GetDesc(D3D11_BLEND_DESC* pDesc) { + pDesc->AlphaToCoverageEnable = m_desc.AlphaToCoverageEnable; + pDesc->IndependentBlendEnable = m_desc.IndependentBlendEnable; + + for (uint32_t i = 0; i < 8; i++) { + pDesc->RenderTarget[i].BlendEnable = m_desc.RenderTarget[i].BlendEnable; + pDesc->RenderTarget[i].SrcBlend = m_desc.RenderTarget[i].SrcBlend; + pDesc->RenderTarget[i].DestBlend = m_desc.RenderTarget[i].DestBlend; + pDesc->RenderTarget[i].BlendOp = m_desc.RenderTarget[i].BlendOp; + pDesc->RenderTarget[i].SrcBlendAlpha = m_desc.RenderTarget[i].SrcBlendAlpha; + pDesc->RenderTarget[i].DestBlendAlpha = m_desc.RenderTarget[i].DestBlendAlpha; + pDesc->RenderTarget[i].BlendOpAlpha = m_desc.RenderTarget[i].BlendOpAlpha; + pDesc->RenderTarget[i].RenderTargetWriteMask = m_desc.RenderTarget[i].RenderTargetWriteMask; + } + } + + + void STDMETHODCALLTYPE D3D11BlendState::GetDesc1(D3D11_BLEND_DESC1* pDesc) { *pDesc = m_desc; } @@ -76,8 +97,62 @@ namespace dxvk { } + D3D11_BLEND_DESC1 D3D11BlendState::DefaultDesc() { + D3D11_BLEND_DESC1 dstDesc; + dstDesc.AlphaToCoverageEnable = FALSE; + dstDesc.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++) { + dstDesc.RenderTarget[i].BlendEnable = FALSE; + dstDesc.RenderTarget[i].LogicOpEnable = FALSE; + dstDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; + dstDesc.RenderTarget[i].DestBlend = D3D11_BLEND_ZERO; + dstDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + dstDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + dstDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ZERO; + dstDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + dstDesc.RenderTarget[i].LogicOp = D3D11_LOGIC_OP_NOOP; + dstDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + } + + return dstDesc; + } + + + D3D11_BLEND_DESC1 D3D11BlendState::PromoteDesc(const D3D11_BLEND_DESC* pSrcDesc) { + D3D11_BLEND_DESC1 dstDesc; + dstDesc.AlphaToCoverageEnable = pSrcDesc->AlphaToCoverageEnable; + dstDesc.IndependentBlendEnable = pSrcDesc->IndependentBlendEnable; + + for (uint32_t i = 0; i < 8; i++) { + dstDesc.RenderTarget[i].BlendEnable = pSrcDesc->RenderTarget[i].BlendEnable; + dstDesc.RenderTarget[i].LogicOpEnable = FALSE; + dstDesc.RenderTarget[i].SrcBlend = pSrcDesc->RenderTarget[i].SrcBlend; + dstDesc.RenderTarget[i].DestBlend = pSrcDesc->RenderTarget[i].DestBlend; + dstDesc.RenderTarget[i].BlendOp = pSrcDesc->RenderTarget[i].BlendOp; + dstDesc.RenderTarget[i].SrcBlendAlpha = pSrcDesc->RenderTarget[i].SrcBlendAlpha; + dstDesc.RenderTarget[i].DestBlendAlpha = pSrcDesc->RenderTarget[i].DestBlendAlpha; + dstDesc.RenderTarget[i].BlendOpAlpha = pSrcDesc->RenderTarget[i].BlendOpAlpha; + dstDesc.RenderTarget[i].LogicOp = D3D11_LOGIC_OP_NOOP; + dstDesc.RenderTarget[i].RenderTargetWriteMask = pSrcDesc->RenderTarget[i].RenderTargetWriteMask; + } + + return dstDesc; + } + + + HRESULT D3D11BlendState::NormalizeDesc(D3D11_BLEND_DESC1* pDesc) { + // TODO validate + // TODO clear unused values + return S_OK; + } + + DxvkBlendMode D3D11BlendState::DecodeBlendMode( - const D3D11_RENDER_TARGET_BLEND_DESC& BlendDesc) { + const D3D11_RENDER_TARGET_BLEND_DESC1& BlendDesc) { DxvkBlendMode mode; mode.enableBlending = BlendDesc.BlendEnable; mode.colorSrcFactor = DecodeBlendFactor(BlendDesc.SrcBlend, false); @@ -132,4 +207,30 @@ namespace dxvk { return VK_BLEND_OP_ADD; } + + VkLogicOp D3D11BlendState::DecodeLogicOp(D3D11_LOGIC_OP LogicOp) { + switch (LogicOp) { + case D3D11_LOGIC_OP_CLEAR: return VK_LOGIC_OP_CLEAR; + case D3D11_LOGIC_OP_SET: return VK_LOGIC_OP_SET; + case D3D11_LOGIC_OP_COPY: return VK_LOGIC_OP_COPY; + case D3D11_LOGIC_OP_COPY_INVERTED: return VK_LOGIC_OP_COPY_INVERTED; + case D3D11_LOGIC_OP_NOOP: return VK_LOGIC_OP_NO_OP; + case D3D11_LOGIC_OP_INVERT: return VK_LOGIC_OP_INVERT; + case D3D11_LOGIC_OP_AND: return VK_LOGIC_OP_AND; + case D3D11_LOGIC_OP_NAND: return VK_LOGIC_OP_NAND; + case D3D11_LOGIC_OP_OR: return VK_LOGIC_OP_OR; + case D3D11_LOGIC_OP_NOR: return VK_LOGIC_OP_NOR; + case D3D11_LOGIC_OP_XOR: return VK_LOGIC_OP_XOR; + case D3D11_LOGIC_OP_EQUIV: return VK_LOGIC_OP_EQUIVALENT; + case D3D11_LOGIC_OP_AND_REVERSE: return VK_LOGIC_OP_AND_REVERSE; + case D3D11_LOGIC_OP_AND_INVERTED: return VK_LOGIC_OP_AND_INVERTED; + case D3D11_LOGIC_OP_OR_REVERSE: return VK_LOGIC_OP_OR_REVERSE; + case D3D11_LOGIC_OP_OR_INVERTED: return VK_LOGIC_OP_OR_INVERTED; + } + + if (LogicOp != 0) + Logger::err(str::format("D3D11: Invalid logic op: ", LogicOp)); + return VK_LOGIC_OP_NO_OP; + } + } diff --git a/src/d3d11/d3d11_blend.h b/src/d3d11/d3d11_blend.h index 25d243e49..c142b9621 100644 --- a/src/d3d11/d3d11_blend.h +++ b/src/d3d11/d3d11_blend.h @@ -9,15 +9,15 @@ namespace dxvk { class D3D11Device; - class D3D11BlendState : public D3D11DeviceChild { + class D3D11BlendState : public D3D11DeviceChild { public: - using DescType = D3D11_BLEND_DESC; + using DescType = D3D11_BLEND_DESC1; D3D11BlendState( - D3D11Device* device, - const D3D11_BLEND_DESC& desc); + D3D11Device* device, + const D3D11_BLEND_DESC1& desc); ~D3D11BlendState(); HRESULT STDMETHODCALLTYPE QueryInterface( @@ -30,21 +30,32 @@ namespace dxvk { void STDMETHODCALLTYPE GetDesc( D3D11_BLEND_DESC* pDesc) final; + void STDMETHODCALLTYPE GetDesc1( + D3D11_BLEND_DESC1* pDesc) final; + void BindToContext( const Rc& ctx, UINT sampleMask) const; + static D3D11_BLEND_DESC1 DefaultDesc(); + + static D3D11_BLEND_DESC1 PromoteDesc( + const D3D11_BLEND_DESC* pSrcDesc); + + static HRESULT NormalizeDesc( + D3D11_BLEND_DESC1* pDesc); + private: D3D11Device* const m_device; - D3D11_BLEND_DESC m_desc; + D3D11_BLEND_DESC1 m_desc; std::array m_blendModes; DxvkMultisampleState m_msState; DxvkLogicOpState m_loState; static DxvkBlendMode DecodeBlendMode( - const D3D11_RENDER_TARGET_BLEND_DESC& BlendDesc); + const D3D11_RENDER_TARGET_BLEND_DESC1& BlendDesc); static VkBlendFactor DecodeBlendFactor( D3D11_BLEND BlendFactor, @@ -53,6 +64,9 @@ namespace dxvk { static VkBlendOp DecodeBlendOp( D3D11_BLEND_OP BlendOp); + static VkLogicOp DecodeLogicOp( + D3D11_LOGIC_OP LogicOp); + }; } diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 94983fc25..affe10753 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -1080,28 +1080,12 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE D3D11Device::CreateBlendState( const D3D11_BLEND_DESC* pBlendStateDesc, ID3D11BlendState** ppBlendState) { - D3D11_BLEND_DESC desc; + D3D11_BLEND_DESC1 desc = pBlendStateDesc != nullptr + ? D3D11BlendState::PromoteDesc(pBlendStateDesc) + : D3D11BlendState::DefaultDesc(); - 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 (FAILED(D3D11BlendState::NormalizeDesc(&desc))) + return E_INVALIDARG; if (ppBlendState != nullptr) { *ppBlendState = m_bsStateObjects.Create(this, desc); @@ -1113,8 +1097,17 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE D3D11Device::CreateBlendState1( const D3D11_BLEND_DESC1* pBlendStateDesc, ID3D11BlendState1** ppBlendState) { - Logger::err("D3D11Device::CreateBlendState1: Not implemented"); - return E_NOTIMPL; + D3D11_BLEND_DESC1 desc = pBlendStateDesc != nullptr + ? *pBlendStateDesc + : D3D11BlendState::DefaultDesc(); + + if (FAILED(D3D11BlendState::NormalizeDesc(&desc))) + return E_INVALIDARG; + + if (ppBlendState != nullptr) { + *ppBlendState = m_bsStateObjects.Create(this, desc); + return S_OK; + } return S_FALSE; } diff --git a/src/d3d11/d3d11_rasterizer.cpp b/src/d3d11/d3d11_rasterizer.cpp index 98d53011f..733317ddf 100644 --- a/src/d3d11/d3d11_rasterizer.cpp +++ b/src/d3d11/d3d11_rasterizer.cpp @@ -72,6 +72,7 @@ namespace dxvk { COM_QUERY_IFACE(riid, ppvObject, IUnknown); COM_QUERY_IFACE(riid, ppvObject, ID3D11DeviceChild); COM_QUERY_IFACE(riid, ppvObject, ID3D11RasterizerState); + COM_QUERY_IFACE(riid, ppvObject, ID3D11RasterizerState1); Logger::warn("D3D11RasterizerState::QueryInterface: Unknown interface query"); Logger::warn(str::format(riid)); diff --git a/src/d3d11/d3d11_state.cpp b/src/d3d11/d3d11_state.cpp index 9c1e767b6..8e9505110 100644 --- a/src/d3d11/d3d11_state.cpp +++ b/src/d3d11/d3d11_state.cpp @@ -3,7 +3,7 @@ namespace dxvk { size_t D3D11StateDescHash::operator () ( - const D3D11_BLEND_DESC& desc) const { + const D3D11_BLEND_DESC1& desc) const { DxvkHashState hash; hash.add(desc.AlphaToCoverageEnable); hash.add(desc.IndependentBlendEnable); @@ -64,15 +64,17 @@ namespace dxvk { size_t D3D11StateDescHash::operator () ( - const D3D11_RENDER_TARGET_BLEND_DESC& desc) const { + const D3D11_RENDER_TARGET_BLEND_DESC1& desc) const { DxvkHashState hash; hash.add(desc.BlendEnable); + hash.add(desc.LogicOpEnable); 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.LogicOp); hash.add(desc.RenderTargetWriteMask); return hash; } @@ -99,8 +101,8 @@ namespace dxvk { bool D3D11StateDescEqual::operator () ( - const D3D11_BLEND_DESC& a, - const D3D11_BLEND_DESC& b) const { + const D3D11_BLEND_DESC1& a, + const D3D11_BLEND_DESC1& b) const { bool eq = a.AlphaToCoverageEnable == b.AlphaToCoverageEnable && a.IndependentBlendEnable == b.IndependentBlendEnable; @@ -157,15 +159,17 @@ namespace dxvk { bool D3D11StateDescEqual::operator () ( - const D3D11_RENDER_TARGET_BLEND_DESC& a, - const D3D11_RENDER_TARGET_BLEND_DESC& b) const { + const D3D11_RENDER_TARGET_BLEND_DESC1& a, + const D3D11_RENDER_TARGET_BLEND_DESC1& b) const { return a.BlendEnable == b.BlendEnable + && a.LogicOpEnable == b.LogicOpEnable && 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.LogicOp == b.LogicOp && a.RenderTargetWriteMask == b.RenderTargetWriteMask; } diff --git a/src/d3d11/d3d11_state.h b/src/d3d11/d3d11_state.h index 7babe8bde..b3319987c 100644 --- a/src/d3d11/d3d11_state.h +++ b/src/d3d11/d3d11_state.h @@ -12,21 +12,21 @@ namespace dxvk { class D3D11Device; struct D3D11StateDescHash { - size_t operator () (const D3D11_BLEND_DESC& desc) const; + size_t operator () (const D3D11_BLEND_DESC1& 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_DESC1& desc) const; - size_t operator () (const D3D11_RENDER_TARGET_BLEND_DESC& desc) const; + size_t operator () (const D3D11_RENDER_TARGET_BLEND_DESC1& desc) const; size_t operator () (const D3D11_SAMPLER_DESC& desc) const; }; struct D3D11StateDescEqual { - bool operator () (const D3D11_BLEND_DESC& a, const D3D11_BLEND_DESC& b) const; + bool operator () (const D3D11_BLEND_DESC1& a, const D3D11_BLEND_DESC1& 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_DESC1& a, const D3D11_RASTERIZER_DESC1& b) const; - bool operator () (const D3D11_RENDER_TARGET_BLEND_DESC& a, const D3D11_RENDER_TARGET_BLEND_DESC& b) const; + bool operator () (const D3D11_RENDER_TARGET_BLEND_DESC1& a, const D3D11_RENDER_TARGET_BLEND_DESC1& b) const; bool operator () (const D3D11_SAMPLER_DESC& a, const D3D11_SAMPLER_DESC& b) const; };