diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/libs/dxvk-native-1.9.2a/src/d3d11 | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libs/dxvk-native-1.9.2a/src/d3d11')
78 files changed, 24180 insertions, 0 deletions
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11.def b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11.def new file mode 100644 index 00000000..8b65655a --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11.def @@ -0,0 +1,5 @@ +LIBRARY D3D11.DLL +EXPORTS + D3D11CoreCreateDevice @18 + D3D11CreateDevice @22 + D3D11CreateDeviceAndSwapChain @23 diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.cpp new file mode 100644 index 00000000..010acdd8 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.cpp @@ -0,0 +1,92 @@ +#include "d3d11_annotation.h" +#include "d3d11_context.h" +#include "d3d11_device.h" + +namespace dxvk { + + D3D11UserDefinedAnnotation::D3D11UserDefinedAnnotation(D3D11DeviceContext* ctx) + : m_container(ctx), + m_eventDepth(0) { } + + + D3D11UserDefinedAnnotation::~D3D11UserDefinedAnnotation() { + + } + + + ULONG STDMETHODCALLTYPE D3D11UserDefinedAnnotation::AddRef() { + return m_container->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11UserDefinedAnnotation::Release() { + return m_container->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11UserDefinedAnnotation::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_container->QueryInterface(riid, ppvObject); + } + + + INT STDMETHODCALLTYPE D3D11UserDefinedAnnotation::BeginEvent( + LPCWSTR Name) { + if (!m_container->IsAnnotationEnabled()) + return -1; + + m_container->EmitCs([labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) { + VkDebugUtilsLabelEXT label; + label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + label.pNext = nullptr; + label.pLabelName = labelName.c_str(); + label.color[0] = 1.0f; + label.color[1] = 1.0f; + label.color[2] = 1.0f; + label.color[3] = 1.0f; + + ctx->beginDebugLabel(&label); + }); + + return m_eventDepth++; + } + + + INT STDMETHODCALLTYPE D3D11UserDefinedAnnotation::EndEvent() { + if (!m_container->IsAnnotationEnabled()) + return -1; + + m_container->EmitCs([](DxvkContext *ctx) { + ctx->endDebugLabel(); + }); + + return m_eventDepth--; + } + + + void STDMETHODCALLTYPE D3D11UserDefinedAnnotation::SetMarker( + LPCWSTR Name) { + if (!m_container->IsAnnotationEnabled()) + return; + + m_container->EmitCs([labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) { + VkDebugUtilsLabelEXT label; + label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + label.pNext = nullptr; + label.pLabelName = labelName.c_str(); + label.color[0] = 1.0f; + label.color[1] = 1.0f; + label.color[2] = 1.0f; + label.color[3] = 1.0f; + + ctx->insertDebugLabel(&label); + }); + } + + + BOOL STDMETHODCALLTYPE D3D11UserDefinedAnnotation::GetStatus() { + return m_container->IsAnnotationEnabled(); + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.h new file mode 100644 index 00000000..97ee39c4 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.h @@ -0,0 +1,42 @@ +#pragma once + +#include "d3d11_include.h" + +namespace dxvk { + + class D3D11DeviceContext; + + class D3D11UserDefinedAnnotation : ID3DUserDefinedAnnotation { + + public: + + D3D11UserDefinedAnnotation(D3D11DeviceContext* ctx); + ~D3D11UserDefinedAnnotation(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + INT STDMETHODCALLTYPE BeginEvent( + LPCWSTR Name); + + INT STDMETHODCALLTYPE EndEvent(); + + void STDMETHODCALLTYPE SetMarker( + LPCWSTR Name); + + BOOL STDMETHODCALLTYPE GetStatus(); + + private: + + D3D11DeviceContext* m_container; + + // Stack depth for non-finalized BeginEvent calls + int32_t m_eventDepth; + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.cpp new file mode 100644 index 00000000..caacc869 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.cpp @@ -0,0 +1,309 @@ +#include "d3d11_blend.h" +#include "d3d11_device.h" + +namespace dxvk { + + D3D11BlendState::D3D11BlendState( + D3D11Device* device, + const D3D11_BLEND_DESC1& desc) + : D3D11StateObject<ID3D11BlendState1>(device), + m_desc(desc), m_d3d10(this) { + // 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; + + // 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); + } + + + D3D11BlendState::~D3D11BlendState() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11BlendState::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11BlendState) + || riid == __uuidof(ID3D11BlendState1)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10BlendState) + || riid == __uuidof(ID3D10BlendState1)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + Logger::warn("D3D11BlendState::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + 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; + } + + + void D3D11BlendState::BindToContext( + const Rc<DxvkContext>& 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); + + // Set up logic op state as well + ctx->setLogicOpState(m_loState); + } + + + 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) { + if (pDesc->AlphaToCoverageEnable) + pDesc->AlphaToCoverageEnable = TRUE; + + if (pDesc->IndependentBlendEnable) + pDesc->IndependentBlendEnable = TRUE; + + const uint32_t numRenderTargets = pDesc->IndependentBlendEnable ? 8 : 1; + + for (uint32_t i = 0; i < numRenderTargets; i++) { + D3D11_RENDER_TARGET_BLEND_DESC1* rt = &pDesc->RenderTarget[i]; + + if (rt->BlendEnable) { + rt->BlendEnable = TRUE; + + if (rt->LogicOpEnable) + return E_INVALIDARG; + + if (!ValidateBlendOperations( + rt->SrcBlend, rt->SrcBlendAlpha, + rt->DestBlend, rt->DestBlendAlpha, + rt->BlendOp, rt->BlendOpAlpha)) + return E_INVALIDARG; + } else { + rt->SrcBlend = D3D11_BLEND_ONE; + rt->DestBlend = D3D11_BLEND_ZERO; + rt->BlendOp = D3D11_BLEND_OP_ADD; + rt->SrcBlendAlpha = D3D11_BLEND_ONE; + rt->DestBlendAlpha = D3D11_BLEND_ZERO; + rt->BlendOpAlpha = D3D11_BLEND_OP_ADD; + } + + if (rt->LogicOpEnable) { + rt->LogicOpEnable = TRUE; + + // Blending must be disabled + // if the logic op is enabled + if (rt->BlendEnable + || pDesc->IndependentBlendEnable + || !ValidateLogicOp(rt->LogicOp)) + return E_INVALIDARG; + } else { + rt->LogicOp = D3D11_LOGIC_OP_NOOP; + } + + if (rt->RenderTargetWriteMask > D3D11_COLOR_WRITE_ENABLE_ALL) + return E_INVALIDARG; + } + + for (uint32_t i = numRenderTargets; i < 8; i++) { + // Render targets blend operations are the same + // across all render targets when blend is enabled + // on rendertarget[0] with independent blend disabled + pDesc->RenderTarget[i] = pDesc->RenderTarget[0]; + } + + return S_OK; + } + + + DxvkBlendMode D3D11BlendState::DecodeBlendMode( + const D3D11_RENDER_TARGET_BLEND_DESC1& 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); + 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; + default: 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; + default: 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; + default: return VK_LOGIC_OP_NO_OP; + } + } + + + bool D3D11BlendState::ValidateBlendFactor(D3D11_BLEND Blend) { + return Blend >= D3D11_BLEND_ZERO + && Blend <= D3D11_BLEND_INV_SRC1_ALPHA; + } + + + bool D3D11BlendState::ValidateBlendFactorAlpha(D3D11_BLEND BlendAlpha) { + return BlendAlpha >= D3D11_BLEND_ZERO + && BlendAlpha <= D3D11_BLEND_INV_SRC1_ALPHA + && BlendAlpha != D3D11_BLEND_SRC_COLOR + && BlendAlpha != D3D11_BLEND_INV_SRC_COLOR + && BlendAlpha != D3D11_BLEND_DEST_COLOR + && BlendAlpha != D3D11_BLEND_INV_DEST_COLOR + && BlendAlpha != D3D11_BLEND_SRC1_COLOR + && BlendAlpha != D3D11_BLEND_INV_SRC1_COLOR; + } + + + bool D3D11BlendState::ValidateBlendOp(D3D11_BLEND_OP BlendOp) { + return BlendOp >= D3D11_BLEND_OP_ADD + && BlendOp <= D3D11_BLEND_OP_MAX; + } + + + bool D3D11BlendState::ValidateLogicOp(D3D11_LOGIC_OP LogicOp) { + return LogicOp >= D3D11_LOGIC_OP_CLEAR + && LogicOp <= D3D11_LOGIC_OP_OR_INVERTED; + } + + + bool D3D11BlendState::ValidateBlendOperations( + D3D11_BLEND SrcBlend, + D3D11_BLEND SrcBlendAlpha, + D3D11_BLEND DestBlend, + D3D11_BLEND DestBlendAlpha, + D3D11_BLEND_OP BlendOp, + D3D11_BLEND_OP BlendOpAlpha) { + return ValidateBlendOp(BlendOp) + && ValidateBlendOp(BlendOpAlpha) + && ValidateBlendFactor(SrcBlend) + && ValidateBlendFactor(DestBlend) + && ValidateBlendFactorAlpha(SrcBlendAlpha) + && ValidateBlendFactorAlpha(DestBlendAlpha); + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.h new file mode 100644 index 00000000..5761d3ca --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.h @@ -0,0 +1,93 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_blend.h" + +#include "d3d11_device_child.h" +#include "d3d11_util.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11BlendState : public D3D11StateObject<ID3D11BlendState1> { + + public: + + using DescType = D3D11_BLEND_DESC1; + + D3D11BlendState( + D3D11Device* device, + const D3D11_BLEND_DESC1& desc); + ~D3D11BlendState(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void STDMETHODCALLTYPE GetDesc( + D3D11_BLEND_DESC* pDesc) final; + + void STDMETHODCALLTYPE GetDesc1( + D3D11_BLEND_DESC1* pDesc) final; + + void BindToContext( + const Rc<DxvkContext>& ctx, + UINT sampleMask) const; + + D3D10BlendState* GetD3D10Iface() { + return &m_d3d10; + } + + static D3D11_BLEND_DESC1 PromoteDesc( + const D3D11_BLEND_DESC* pSrcDesc); + + static HRESULT NormalizeDesc( + D3D11_BLEND_DESC1* pDesc); + + private: + + D3D11_BLEND_DESC1 m_desc; + + std::array<DxvkBlendMode, 8> m_blendModes; + DxvkMultisampleState m_msState; + DxvkLogicOpState m_loState; + + D3D10BlendState m_d3d10; + + static DxvkBlendMode DecodeBlendMode( + const D3D11_RENDER_TARGET_BLEND_DESC1& BlendDesc); + + static VkBlendFactor DecodeBlendFactor( + D3D11_BLEND BlendFactor, + bool IsAlpha); + + static VkBlendOp DecodeBlendOp( + D3D11_BLEND_OP BlendOp); + + static VkLogicOp DecodeLogicOp( + D3D11_LOGIC_OP LogicOp); + + static bool ValidateBlendFactor( + D3D11_BLEND Blend); + + static bool ValidateBlendFactorAlpha( + D3D11_BLEND BlendAlpha); + + static bool ValidateBlendOp( + D3D11_BLEND_OP BlendOp); + + static bool ValidateLogicOp( + D3D11_LOGIC_OP LogicOp); + + static bool ValidateBlendOperations( + D3D11_BLEND SrcBlend, + D3D11_BLEND SrcBlendAlpha, + D3D11_BLEND SestBlend, + D3D11_BLEND DestBlendAlpha, + D3D11_BLEND_OP BlendOp, + D3D11_BLEND_OP BlendOpAlpha); + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.cpp new file mode 100644 index 00000000..687be0a5 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.cpp @@ -0,0 +1,287 @@ +#include "d3d11_buffer.h" +#include "d3d11_context.h" +#include "d3d11_device.h" + +#include "../dxvk/dxvk_data.h" + +namespace dxvk { + + D3D11Buffer::D3D11Buffer( + D3D11Device* pDevice, + const D3D11_BUFFER_DESC* pDesc) + : D3D11DeviceChild<ID3D11Buffer>(pDevice), + m_desc (*pDesc), + m_resource (this), + m_d3d10 (this) { + DxvkBufferCreateInfo info; + info.size = pDesc->ByteWidth; + info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT; + info.access = VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_TRANSFER_WRITE_BIT; + + if (pDesc->BindFlags & D3D11_BIND_VERTEX_BUFFER) { + info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + info.access |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + } + + if (pDesc->BindFlags & D3D11_BIND_INDEX_BUFFER) { + info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + info.access |= VK_ACCESS_INDEX_READ_BIT; + } + + if (pDesc->BindFlags & D3D11_BIND_CONSTANT_BUFFER) { + info.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + info.stages |= m_parent->GetEnabledShaderStages(); + info.access |= VK_ACCESS_UNIFORM_READ_BIT; + + if (m_parent->GetOptions()->constantBufferRangeCheck) + info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + } + + if (pDesc->BindFlags & D3D11_BIND_SHADER_RESOURCE) { + info.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT + | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + info.stages |= m_parent->GetEnabledShaderStages(); + info.access |= VK_ACCESS_SHADER_READ_BIT; + } + + if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT) { + info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; + info.stages |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; + info.access |= VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT; + } + + if (pDesc->BindFlags & D3D11_BIND_UNORDERED_ACCESS) { + info.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT + | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + info.stages |= m_parent->GetEnabledShaderStages(); + info.access |= VK_ACCESS_SHADER_READ_BIT + | VK_ACCESS_SHADER_WRITE_BIT; + } + + if (pDesc->MiscFlags & D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS) { + info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; + info.stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; + info.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + } + + // Create the buffer and set the entire buffer slice as mapped, + // so that we only have to update it when invalidating th buffer + m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, GetMemoryFlags()); + m_mapped = m_buffer->getSliceHandle(); + + // For Stream Output buffers we need a counter + if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT) + m_soCounter = CreateSoCounterBuffer(); + } + + + D3D11Buffer::~D3D11Buffer() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11Buffer::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11Resource) + || riid == __uuidof(ID3D11Buffer)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10Resource) + || riid == __uuidof(ID3D10Buffer)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + if (riid == __uuidof(IDXGIObject) + || riid == __uuidof(IDXGIDeviceSubObject) + || riid == __uuidof(IDXGIResource) + || riid == __uuidof(IDXGIResource1)) { + *ppvObject = ref(&m_resource); + return S_OK; + } + + Logger::warn("D3D11Buffer::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + UINT STDMETHODCALLTYPE D3D11Buffer::GetEvictionPriority() { + return DXGI_RESOURCE_PRIORITY_NORMAL; + } + + + void STDMETHODCALLTYPE D3D11Buffer::SetEvictionPriority(UINT EvictionPriority) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11Buffer::SetEvictionPriority: Stub"); + } + + + void STDMETHODCALLTYPE D3D11Buffer::GetType(D3D11_RESOURCE_DIMENSION* pResourceDimension) { + *pResourceDimension = D3D11_RESOURCE_DIMENSION_BUFFER; + } + + + void STDMETHODCALLTYPE D3D11Buffer::GetDesc(D3D11_BUFFER_DESC* pDesc) { + *pDesc = m_desc; + } + + + bool D3D11Buffer::CheckViewCompatibility( + UINT BindFlags, + DXGI_FORMAT Format) const { + // Check whether the given bind flags are supported + if ((m_desc.BindFlags & BindFlags) != BindFlags) + return false; + + // Structured buffer views use no format + if (Format == DXGI_FORMAT_UNKNOWN) + return (m_desc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) != 0; + + // Check whether the given combination of buffer view + // type and view format is supported by the device + DXGI_VK_FORMAT_INFO viewFormat = m_parent->LookupFormat(Format, DXGI_VK_FORMAT_MODE_ANY); + VkFormatFeatureFlags features = GetBufferFormatFeatures(BindFlags); + + return CheckFormatFeatureSupport(viewFormat.Format, features); + } + + + HRESULT D3D11Buffer::NormalizeBufferProperties(D3D11_BUFFER_DESC* pDesc) { + // Zero-sized buffers are illegal + if (!pDesc->ByteWidth) + return E_INVALIDARG; + + // We don't support tiled resources + if (pDesc->MiscFlags & (D3D11_RESOURCE_MISC_TILE_POOL | D3D11_RESOURCE_MISC_TILED)) + return E_INVALIDARG; + + // Constant buffer size must be a multiple of 16 + if ((pDesc->BindFlags & D3D11_BIND_CONSTANT_BUFFER) + && (pDesc->ByteWidth & 0xF)) + return E_INVALIDARG; + + // Basic validation for structured buffers + if ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) + && ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) + || (pDesc->StructureByteStride == 0) + || (pDesc->StructureByteStride & 0x3))) + return E_INVALIDARG; + + // Basic validation for raw buffers + if ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) + && (!(pDesc->BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS)))) + return E_INVALIDARG; + + // Mip generation obviously doesn't work for buffers + if (pDesc->MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS) + return E_INVALIDARG; + + if (!(pDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED)) + pDesc->StructureByteStride = 0; + + return S_OK; + } + + + BOOL D3D11Buffer::CheckFormatFeatureSupport( + VkFormat Format, + VkFormatFeatureFlags Features) const { + VkFormatProperties properties = m_parent->GetDXVKDevice()->adapter()->formatProperties(Format); + return (properties.bufferFeatures & Features) == Features; + } + + + VkMemoryPropertyFlags D3D11Buffer::GetMemoryFlags() const { + VkMemoryPropertyFlags memoryFlags = 0; + + switch (m_desc.Usage) { + case D3D11_USAGE_IMMUTABLE: + memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + break; + + case D3D11_USAGE_DEFAULT: + memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + if ((m_desc.BindFlags & D3D11_BIND_CONSTANT_BUFFER) || m_desc.CPUAccessFlags) { + memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + } + + if (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) { + memoryFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + memoryFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + break; + + case D3D11_USAGE_DYNAMIC: + memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + if (m_desc.BindFlags) + memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + break; + + case D3D11_USAGE_STAGING: + memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + break; + } + + if (memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT && m_parent->GetOptions()->apitraceMode) { + memoryFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + + return memoryFlags; + } + + + Rc<DxvkBuffer> D3D11Buffer::CreateSoCounterBuffer() { + Rc<DxvkDevice> device = m_parent->GetDXVKDevice(); + + DxvkBufferCreateInfo info; + info.size = sizeof(D3D11SOCounter); + info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_TRANSFER_SRC_BIT + | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT; + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT + | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT + | VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; + info.access = VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_TRANSFER_WRITE_BIT + | VK_ACCESS_INDIRECT_COMMAND_READ_BIT + | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT + | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT; + return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + + + D3D11Buffer* GetCommonBuffer(ID3D11Resource* pResource) { + D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&dimension); + + return dimension == D3D11_RESOURCE_DIMENSION_BUFFER + ? static_cast<D3D11Buffer*>(pResource) + : nullptr; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.h new file mode 100644 index 00000000..3ddd61a0 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.h @@ -0,0 +1,162 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_buffer.h" + +#include "d3d11_device_child.h" +#include "d3d11_interfaces.h" +#include "d3d11_resource.h" + +namespace dxvk { + + class D3D11Device; + class D3D11DeviceContext; + + + /** + * \brief Buffer map mode + */ + enum D3D11_COMMON_BUFFER_MAP_MODE { + D3D11_COMMON_BUFFER_MAP_MODE_NONE, + D3D11_COMMON_BUFFER_MAP_MODE_DIRECT, + }; + + + /** + * \brief Stream output buffer offset + * + * A byte offset into the buffer that + * stores the byte offset where new + * data will be written to. + */ + struct D3D11SOCounter { + uint32_t byteOffset; + }; + + + class D3D11Buffer : public D3D11DeviceChild<ID3D11Buffer> { + static constexpr VkDeviceSize BufferSliceAlignment = 64; + public: + + D3D11Buffer( + D3D11Device* pDevice, + const D3D11_BUFFER_DESC* pDesc); + ~D3D11Buffer(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void STDMETHODCALLTYPE GetType( + D3D11_RESOURCE_DIMENSION *pResourceDimension) final; + + UINT STDMETHODCALLTYPE GetEvictionPriority() final; + + void STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) final; + + void STDMETHODCALLTYPE GetDesc( + D3D11_BUFFER_DESC *pDesc) final; + + bool CheckViewCompatibility( + UINT BindFlags, + DXGI_FORMAT Format) const; + + const D3D11_BUFFER_DESC* Desc() const { + return &m_desc; + } + + D3D11_COMMON_BUFFER_MAP_MODE GetMapMode() const { + return (m_buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + ? D3D11_COMMON_BUFFER_MAP_MODE_DIRECT + : D3D11_COMMON_BUFFER_MAP_MODE_NONE; + } + + Rc<DxvkBuffer> GetBuffer() const { + return m_buffer; + } + + DxvkBufferSlice GetBufferSlice() const { + return DxvkBufferSlice(m_buffer, 0, m_desc.ByteWidth); + } + + DxvkBufferSlice GetBufferSlice(VkDeviceSize offset) const { + VkDeviceSize size = m_desc.ByteWidth; + + return likely(offset < size) + ? DxvkBufferSlice(m_buffer, offset, size - offset) + : DxvkBufferSlice(); + } + + DxvkBufferSlice GetBufferSlice(VkDeviceSize offset, VkDeviceSize length) const { + VkDeviceSize size = m_desc.ByteWidth; + + return likely(offset < size) + ? DxvkBufferSlice(m_buffer, offset, std::min(length, size - offset)) + : DxvkBufferSlice(); + } + + DxvkBufferSlice GetSOCounter() { + return m_soCounter != nullptr + ? DxvkBufferSlice(m_soCounter) + : DxvkBufferSlice(); + } + + DxvkBufferSliceHandle AllocSlice() { + return m_buffer->allocSlice(); + } + + DxvkBufferSliceHandle DiscardSlice() { + m_mapped = m_buffer->allocSlice(); + return m_mapped; + } + + DxvkBufferSliceHandle GetMappedSlice() const { + return m_mapped; + } + + D3D10Buffer* GetD3D10Iface() { + return &m_d3d10; + } + + /** + * \brief Normalizes buffer description + * + * \param [in] pDesc Buffer description + * \returns \c S_OK if the parameters are valid + */ + static HRESULT NormalizeBufferProperties( + D3D11_BUFFER_DESC* pDesc); + + private: + + const D3D11_BUFFER_DESC m_desc; + + Rc<DxvkBuffer> m_buffer; + Rc<DxvkBuffer> m_soCounter; + DxvkBufferSliceHandle m_mapped; + + D3D11DXGIResource m_resource; + D3D10Buffer m_d3d10; + + BOOL CheckFormatFeatureSupport( + VkFormat Format, + VkFormatFeatureFlags Features) const; + + VkMemoryPropertyFlags GetMemoryFlags() const; + + Rc<DxvkBuffer> CreateSoCounterBuffer(); + + }; + + + /** + * \brief Retrieves buffer from resource pointer + * + * \param [in] pResource The resource to query + * \returns Pointer to buffer, or \c nullptr + */ + D3D11Buffer* GetCommonBuffer( + ID3D11Resource* pResource); + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.cpp new file mode 100644 index 00000000..8070b660 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.cpp @@ -0,0 +1,59 @@ +#include "d3d11_class_linkage.h" +#include "d3d11_device.h" + +namespace dxvk { + + D3D11ClassLinkage::D3D11ClassLinkage( + D3D11Device* pDevice) + : D3D11DeviceChild<ID3D11ClassLinkage>(pDevice) { + + } + + + D3D11ClassLinkage::~D3D11ClassLinkage() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11ClassLinkage::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11ClassLinkage)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11ClassLinkage::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + HRESULT STDMETHODCALLTYPE D3D11ClassLinkage::CreateClassInstance( + LPCSTR pClassTypeName, + UINT ConstantBufferOffset, + UINT ConstantVectorOffset, + UINT TextureOffset, + UINT SamplerOffset, + ID3D11ClassInstance **ppInstance) { + InitReturnPtr(ppInstance); + + Logger::err("D3D11ClassLinkage::CreateClassInstance: Not implemented yet"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11ClassLinkage::GetClassInstance( + LPCSTR pClassInstanceName, + UINT InstanceIndex, + ID3D11ClassInstance **ppInstance) { + Logger::err("D3D11ClassLinkage::GetClassInstance: Not implemented yet"); + return E_NOTIMPL; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.h new file mode 100644 index 00000000..7d1c324c --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.h @@ -0,0 +1,38 @@ +#pragma once + +#include "d3d11_device_child.h" + +namespace dxvk { + + class D3D11Device; + + // TODO implement properly + class D3D11ClassLinkage : public D3D11DeviceChild<ID3D11ClassLinkage> { + + public: + + D3D11ClassLinkage( + D3D11Device* pDevice); + + ~D3D11ClassLinkage(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + HRESULT STDMETHODCALLTYPE CreateClassInstance( + LPCSTR pClassTypeName, + UINT ConstantBufferOffset, + UINT ConstantVectorOffset, + UINT TextureOffset, + UINT SamplerOffset, + ID3D11ClassInstance **ppInstance); + + HRESULT STDMETHODCALLTYPE GetClassInstance( + LPCSTR pClassInstanceName, + UINT InstanceIndex, + ID3D11ClassInstance **ppInstance); + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmd.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmd.h new file mode 100644 index 00000000..52f2f4db --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmd.h @@ -0,0 +1,43 @@ +#pragma once + +#include "d3d11_include.h" + +namespace dxvk { + + /** + * \brief D3D11 command type + * + * Used to identify the type of command + * data most recently added to a CS chunk. + */ + enum class D3D11CmdType { + DrawIndirect, + DrawIndirectIndexed, + }; + + + /** + * \brief Command data header + * + * Stores the command type. All command + * data structs must inherit this struct. + */ + struct D3D11CmdData { + D3D11CmdType type; + }; + + + /** + * \brief Indirect draw command data + * + * Stores the offset into the draw buffer for + * the first draw, as well as the number of + * draws to execute. + */ + struct D3D11CmdDrawIndirectData : public D3D11CmdData { + uint32_t offset; + uint32_t count; + uint32_t stride; + }; + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.cpp new file mode 100644 index 00000000..0ce56211 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.cpp @@ -0,0 +1,85 @@ +#include "d3d11_cmdlist.h" +#include "d3d11_device.h" + +namespace dxvk { + + D3D11CommandList::D3D11CommandList( + D3D11Device* pDevice, + UINT ContextFlags) + : D3D11DeviceChild<ID3D11CommandList>(pDevice), + m_contextFlags(ContextFlags) { } + + + D3D11CommandList::~D3D11CommandList() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11CommandList::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11CommandList)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11CommandList::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + UINT STDMETHODCALLTYPE D3D11CommandList::GetContextFlags() { + return m_contextFlags; + } + + + void D3D11CommandList::AddChunk(DxvkCsChunkRef&& Chunk) { + m_chunks.push_back(std::move(Chunk)); + } + + + void D3D11CommandList::AddQuery(D3D11Query* pQuery) { + m_queries.emplace_back(pQuery); + } + + + void D3D11CommandList::EmitToCommandList(ID3D11CommandList* pCommandList) { + auto cmdList = static_cast<D3D11CommandList*>(pCommandList); + + for (const auto& chunk : m_chunks) + cmdList->m_chunks.push_back(chunk); + + for (const auto& query : m_queries) + cmdList->m_queries.push_back(query); + + MarkSubmitted(); + } + + + void D3D11CommandList::EmitToCsThread(DxvkCsThread* CsThread) { + for (const auto& query : m_queries) + query->DoDeferredEnd(); + + for (const auto& chunk : m_chunks) + CsThread->dispatchChunk(DxvkCsChunkRef(chunk)); + + MarkSubmitted(); + } + + + void D3D11CommandList::MarkSubmitted() { + if (m_submitted.exchange(true) && !m_warned.exchange(true) + && m_parent->GetOptions()->dcSingleUseMode) { + Logger::warn( + "D3D11: Command list submitted multiple times,\n" + " but d3d11.dcSingleUseMode is enabled"); + } + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.h new file mode 100644 index 00000000..ce207aaf --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.h @@ -0,0 +1,49 @@ +#pragma once + +#include "d3d11_context.h" + +namespace dxvk { + + class D3D11CommandList : public D3D11DeviceChild<ID3D11CommandList> { + + public: + + D3D11CommandList( + D3D11Device* pDevice, + UINT ContextFlags); + + ~D3D11CommandList(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + UINT STDMETHODCALLTYPE GetContextFlags() final; + + void AddChunk( + DxvkCsChunkRef&& Chunk); + + void AddQuery( + D3D11Query* pQuery); + + void EmitToCommandList( + ID3D11CommandList* pCommandList); + + void EmitToCsThread( + DxvkCsThread* CsThread); + + private: + + UINT const m_contextFlags; + + std::vector<DxvkCsChunkRef> m_chunks; + std::vector<Com<D3D11Query, false>> m_queries; + + std::atomic<bool> m_submitted = { false }; + std::atomic<bool> m_warned = { false }; + + void MarkSubmitted(); + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp new file mode 100644 index 00000000..45af2f7b --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp @@ -0,0 +1,4507 @@ +#include <cstring> + +#include "d3d11_context.h" +#include "d3d11_device.h" +#include "d3d11_query.h" +#include "d3d11_texture.h" +#include "d3d11_video.h" + +#include "../dxbc/dxbc_util.h" + +namespace dxvk { + + D3D11DeviceContext::D3D11DeviceContext( + D3D11Device* pParent, + const Rc<DxvkDevice>& Device, + DxvkCsChunkFlags CsFlags) + : D3D11DeviceChild<ID3D11DeviceContext4>(pParent), + m_contextExt(this), + m_annotation(this), + m_multithread(this, false), + m_device (Device), + m_csFlags (CsFlags), + m_csChunk (AllocCsChunk()), + m_cmdData (nullptr) { + + } + + + D3D11DeviceContext::~D3D11DeviceContext() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11DeviceContext::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11DeviceContext) + || riid == __uuidof(ID3D11DeviceContext1) + || riid == __uuidof(ID3D11DeviceContext2) + || riid == __uuidof(ID3D11DeviceContext3) + || riid == __uuidof(ID3D11DeviceContext4)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D11VkExtContext) + || riid == __uuidof(ID3D11VkExtContext1)) { + *ppvObject = ref(&m_contextExt); + return S_OK; + } + + if (riid == __uuidof(ID3DUserDefinedAnnotation)) { + *ppvObject = ref(&m_annotation); + return S_OK; + } + + if (riid == __uuidof(ID3D10Multithread)) { + *ppvObject = ref(&m_multithread); + return S_OK; + } + + Logger::warn("D3D11DeviceContext::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DiscardResource(ID3D11Resource* pResource) { + D3D10DeviceLock lock = LockContext(); + + if (!pResource) + return; + + // We don't support the Discard API for images + D3D11_RESOURCE_DIMENSION resType = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resType); + + if (resType == D3D11_RESOURCE_DIMENSION_BUFFER) { + DiscardBuffer(pResource); + } else { + auto texture = GetCommonTexture(pResource); + + for (uint32_t i = 0; i < texture->CountSubresources(); i++) + DiscardTexture(pResource, i); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DiscardView(ID3D11View* pResourceView) { + DiscardView1(pResourceView, nullptr, 0); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DiscardView1( + ID3D11View* pResourceView, + const D3D11_RECT* pRects, + UINT NumRects) { + D3D10DeviceLock lock = LockContext(); + + // We don't support discarding individual rectangles + if (!pResourceView || (NumRects && pRects)) + return; + + // ID3D11View has no methods to query the exact type of + // the view, so we'll have to check each possible class + auto dsv = dynamic_cast<D3D11DepthStencilView*>(pResourceView); + auto rtv = dynamic_cast<D3D11RenderTargetView*>(pResourceView); + auto uav = dynamic_cast<D3D11UnorderedAccessView*>(pResourceView); + + Rc<DxvkImageView> view; + if (dsv) view = dsv->GetImageView(); + if (rtv) view = rtv->GetImageView(); + if (uav) view = uav->GetImageView(); + + if (view == nullptr) + return; + + // Get information about underlying resource + Com<ID3D11Resource> resource; + pResourceView->GetResource(&resource); + + uint32_t mipCount = GetCommonTexture(resource.ptr())->Desc()->MipLevels; + + // Discard mip levels one by one + VkImageSubresourceRange sr = view->subresources(); + + for (uint32_t layer = 0; layer < sr.layerCount; layer++) { + for (uint32_t mip = 0; mip < sr.levelCount; mip++) { + DiscardTexture(resource.ptr(), D3D11CalcSubresource( + sr.baseMipLevel + mip, sr.baseArrayLayer + layer, mipCount)); + } + } + + // Since we don't handle SRVs here, we can assume that the + // view covers all aspects of the underlying resource. + EmitCs([cView = view] (DxvkContext* ctx) { + ctx->discardImageView(cView, cView->formatInfo()->aspectMask); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::ClearState() { + D3D10DeviceLock lock = LockContext(); + + // Default shaders + m_state.vs.shader = nullptr; + m_state.hs.shader = nullptr; + m_state.ds.shader = nullptr; + m_state.gs.shader = nullptr; + m_state.ps.shader = nullptr; + m_state.cs.shader = nullptr; + + // Default constant buffers + for (uint32_t i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) { + m_state.vs.constantBuffers[i] = { nullptr, 0, 0 }; + m_state.hs.constantBuffers[i] = { nullptr, 0, 0 }; + m_state.ds.constantBuffers[i] = { nullptr, 0, 0 }; + m_state.gs.constantBuffers[i] = { nullptr, 0, 0 }; + m_state.ps.constantBuffers[i] = { nullptr, 0, 0 }; + m_state.cs.constantBuffers[i] = { nullptr, 0, 0 }; + } + + // Default samplers + for (uint32_t i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++) { + m_state.vs.samplers[i] = nullptr; + m_state.hs.samplers[i] = nullptr; + m_state.ds.samplers[i] = nullptr; + m_state.gs.samplers[i] = nullptr; + m_state.ps.samplers[i] = nullptr; + m_state.cs.samplers[i] = nullptr; + } + + // Default shader resources + for (uint32_t i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) { + m_state.vs.shaderResources.views[i] = nullptr; + m_state.hs.shaderResources.views[i] = nullptr; + m_state.ds.shaderResources.views[i] = nullptr; + m_state.gs.shaderResources.views[i] = nullptr; + m_state.ps.shaderResources.views[i] = nullptr; + m_state.cs.shaderResources.views[i] = nullptr; + } + + m_state.vs.shaderResources.hazardous.clear(); + m_state.hs.shaderResources.hazardous.clear(); + m_state.ds.shaderResources.hazardous.clear(); + m_state.gs.shaderResources.hazardous.clear(); + m_state.ps.shaderResources.hazardous.clear(); + m_state.cs.shaderResources.hazardous.clear(); + + // Default UAVs + for (uint32_t i = 0; i < D3D11_1_UAV_SLOT_COUNT; i++) { + m_state.ps.unorderedAccessViews[i] = nullptr; + m_state.cs.unorderedAccessViews[i] = nullptr; + } + + m_state.cs.uavMask.clear(); + + // Default ID state + m_state.id.argBuffer = nullptr; + + // Default IA state + m_state.ia.inputLayout = nullptr; + m_state.ia.primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + + for (uint32_t i = 0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) { + m_state.ia.vertexBuffers[i].buffer = nullptr; + m_state.ia.vertexBuffers[i].offset = 0; + m_state.ia.vertexBuffers[i].stride = 0; + } + + m_state.ia.indexBuffer.buffer = nullptr; + m_state.ia.indexBuffer.offset = 0; + m_state.ia.indexBuffer.format = DXGI_FORMAT_UNKNOWN; + + // Default OM State + for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + m_state.om.renderTargetViews[i] = nullptr; + m_state.om.depthStencilView = nullptr; + + m_state.om.cbState = nullptr; + m_state.om.dsState = nullptr; + + for (uint32_t i = 0; i < 4; i++) + m_state.om.blendFactor[i] = 1.0f; + + m_state.om.sampleMask = D3D11_DEFAULT_SAMPLE_MASK; + m_state.om.stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE; + + m_state.om.maxRtv = 0; + m_state.om.maxUav = 0; + + // Default RS state + m_state.rs.state = nullptr; + m_state.rs.numViewports = 0; + m_state.rs.numScissors = 0; + + for (uint32_t i = 0; i < D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; i++) { + m_state.rs.viewports[i] = D3D11_VIEWPORT { }; + m_state.rs.scissors [i] = D3D11_RECT { }; + } + + // Default SO state + for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) { + m_state.so.targets[i].buffer = nullptr; + m_state.so.targets[i].offset = 0; + } + + // Default predication + m_state.pr.predicateObject = nullptr; + m_state.pr.predicateValue = FALSE; + + // Make sure to apply all state + ResetState(); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::SetPredication( + ID3D11Predicate* pPredicate, + BOOL PredicateValue) { + D3D10DeviceLock lock = LockContext(); + + auto predicate = D3D11Query::FromPredicate(pPredicate); + m_state.pr.predicateObject = predicate; + m_state.pr.predicateValue = PredicateValue; + + static bool s_errorShown = false; + + if (pPredicate && !std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::SetPredication: Stub"); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GetPredication( + ID3D11Predicate** ppPredicate, + BOOL* pPredicateValue) { + D3D10DeviceLock lock = LockContext(); + + if (ppPredicate) + *ppPredicate = D3D11Query::AsPredicate(m_state.pr.predicateObject.ref()); + + if (pPredicateValue) + *pPredicateValue = m_state.pr.predicateValue; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CopySubresourceRegion( + ID3D11Resource* pDstResource, + UINT DstSubresource, + UINT DstX, + UINT DstY, + UINT DstZ, + ID3D11Resource* pSrcResource, + UINT SrcSubresource, + const D3D11_BOX* pSrcBox) { + CopySubresourceRegion1( + pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, pSrcBox, 0); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CopySubresourceRegion1( + ID3D11Resource* pDstResource, + UINT DstSubresource, + UINT DstX, + UINT DstY, + UINT DstZ, + ID3D11Resource* pSrcResource, + UINT SrcSubresource, + const D3D11_BOX* pSrcBox, + UINT CopyFlags) { + D3D10DeviceLock lock = LockContext(); + + if (!pDstResource || !pSrcResource) + return; + + if (pSrcBox + && (pSrcBox->left >= pSrcBox->right + || pSrcBox->top >= pSrcBox->bottom + || pSrcBox->front >= pSrcBox->back)) + return; + + D3D11_RESOURCE_DIMENSION dstResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + D3D11_RESOURCE_DIMENSION srcResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + + pDstResource->GetType(&dstResourceDim); + pSrcResource->GetType(&srcResourceDim); + + if (dstResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER && srcResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) { + auto dstBuffer = static_cast<D3D11Buffer*>(pDstResource); + auto srcBuffer = static_cast<D3D11Buffer*>(pSrcResource); + + VkDeviceSize dstOffset = DstX; + VkDeviceSize srcOffset = 0; + VkDeviceSize byteCount = -1; + + if (pSrcBox) { + srcOffset = pSrcBox->left; + byteCount = pSrcBox->right - pSrcBox->left; + } + + CopyBuffer(dstBuffer, dstOffset, srcBuffer, srcOffset, byteCount); + } else if (dstResourceDim != D3D11_RESOURCE_DIMENSION_BUFFER && srcResourceDim != D3D11_RESOURCE_DIMENSION_BUFFER) { + auto dstTexture = GetCommonTexture(pDstResource); + auto srcTexture = GetCommonTexture(pSrcResource); + + if (DstSubresource >= dstTexture->CountSubresources() + || SrcSubresource >= srcTexture->CountSubresources()) + return; + + auto dstFormatInfo = imageFormatInfo(dstTexture->GetPackedFormat()); + auto srcFormatInfo = imageFormatInfo(srcTexture->GetPackedFormat()); + + auto dstLayers = vk::makeSubresourceLayers(dstTexture->GetSubresourceFromIndex(dstFormatInfo->aspectMask, DstSubresource)); + auto srcLayers = vk::makeSubresourceLayers(srcTexture->GetSubresourceFromIndex(srcFormatInfo->aspectMask, SrcSubresource)); + + VkOffset3D srcOffset = { 0, 0, 0 }; + VkOffset3D dstOffset = { int32_t(DstX), int32_t(DstY), int32_t(DstZ) }; + + VkExtent3D srcExtent = srcTexture->MipLevelExtent(srcLayers.mipLevel); + + if (pSrcBox != nullptr) { + srcOffset.x = pSrcBox->left; + srcOffset.y = pSrcBox->top; + srcOffset.z = pSrcBox->front; + + srcExtent.width = pSrcBox->right - pSrcBox->left; + srcExtent.height = pSrcBox->bottom - pSrcBox->top; + srcExtent.depth = pSrcBox->back - pSrcBox->front; + } + + CopyImage( + dstTexture, &dstLayers, dstOffset, + srcTexture, &srcLayers, srcOffset, + srcExtent); + } else { + Logger::err(str::format( + "D3D11: CopySubresourceRegion1: Incompatible resources", + "\n Dst resource type: ", dstResourceDim, + "\n Src resource type: ", srcResourceDim)); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CopyResource( + ID3D11Resource* pDstResource, + ID3D11Resource* pSrcResource) { + D3D10DeviceLock lock = LockContext(); + + if (!pDstResource || !pSrcResource || (pDstResource == pSrcResource)) + return; + + D3D11_RESOURCE_DIMENSION dstResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + D3D11_RESOURCE_DIMENSION srcResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + + pDstResource->GetType(&dstResourceDim); + pSrcResource->GetType(&srcResourceDim); + + if (dstResourceDim != srcResourceDim) { + Logger::err(str::format( + "D3D11: CopyResource: Incompatible resources", + "\n Dst resource type: ", dstResourceDim, + "\n Src resource type: ", srcResourceDim)); + return; + } + + if (dstResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) { + auto dstBuffer = static_cast<D3D11Buffer*>(pDstResource); + auto srcBuffer = static_cast<D3D11Buffer*>(pSrcResource); + + if (dstBuffer->Desc()->ByteWidth != srcBuffer->Desc()->ByteWidth) + return; + + CopyBuffer(dstBuffer, 0, srcBuffer, 0, -1); + } else { + auto dstTexture = GetCommonTexture(pDstResource); + auto srcTexture = GetCommonTexture(pSrcResource); + + auto dstDesc = dstTexture->Desc(); + auto srcDesc = srcTexture->Desc(); + + // The subresource count must match as well + if (dstDesc->ArraySize != srcDesc->ArraySize + || dstDesc->MipLevels != srcDesc->MipLevels) { + Logger::err("D3D11: CopyResource: Incompatible images"); + return; + } + + auto dstFormatInfo = imageFormatInfo(dstTexture->GetPackedFormat()); + auto srcFormatInfo = imageFormatInfo(srcTexture->GetPackedFormat()); + + for (uint32_t i = 0; i < dstDesc->MipLevels; i++) { + VkImageSubresourceLayers dstLayers = { dstFormatInfo->aspectMask, i, 0, dstDesc->ArraySize }; + VkImageSubresourceLayers srcLayers = { srcFormatInfo->aspectMask, i, 0, srcDesc->ArraySize }; + + CopyImage( + dstTexture, &dstLayers, VkOffset3D(), + srcTexture, &srcLayers, VkOffset3D(), + srcTexture->MipLevelExtent(i)); + } + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CopyStructureCount( + ID3D11Buffer* pDstBuffer, + UINT DstAlignedByteOffset, + ID3D11UnorderedAccessView* pSrcView) { + D3D10DeviceLock lock = LockContext(); + + auto buf = static_cast<D3D11Buffer*>(pDstBuffer); + auto uav = static_cast<D3D11UnorderedAccessView*>(pSrcView); + + if (!buf || !uav) + return; + + auto counterSlice = uav->GetCounterSlice(); + if (!counterSlice.defined()) + return; + + EmitCs([ + cDstSlice = buf->GetBufferSlice(DstAlignedByteOffset), + cSrcSlice = std::move(counterSlice) + ] (DxvkContext* ctx) { + ctx->copyBuffer( + cDstSlice.buffer(), + cDstSlice.offset(), + cSrcSlice.buffer(), + cSrcSlice.offset(), + sizeof(uint32_t)); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CopyTiles( + ID3D11Resource* pTiledResource, + const D3D11_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate, + const D3D11_TILE_REGION_SIZE* pTileRegionSize, + ID3D11Buffer* pBuffer, + UINT64 BufferStartOffsetInBytes, + UINT Flags) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::CopyTiles: Not implemented"); + } + + + HRESULT STDMETHODCALLTYPE D3D11DeviceContext::CopyTileMappings( + ID3D11Resource* pDestTiledResource, + const D3D11_TILED_RESOURCE_COORDINATE* pDestRegionStartCoordinate, + ID3D11Resource* pSourceTiledResource, + const D3D11_TILED_RESOURCE_COORDINATE* pSourceRegionStartCoordinate, + const D3D11_TILE_REGION_SIZE* pTileRegionSize, + UINT Flags) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::CopyTileMappings: Not implemented"); + + return DXGI_ERROR_INVALID_CALL; + } + + + HRESULT STDMETHODCALLTYPE D3D11DeviceContext::ResizeTilePool( + ID3D11Buffer* pTilePool, + UINT64 NewSizeInBytes) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::ResizeTilePool: Not implemented"); + + return DXGI_ERROR_INVALID_CALL; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::TiledResourceBarrier( + ID3D11DeviceChild* pTiledResourceOrViewAccessBeforeBarrier, + ID3D11DeviceChild* pTiledResourceOrViewAccessAfterBarrier) { + + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::ClearRenderTargetView( + ID3D11RenderTargetView* pRenderTargetView, + const FLOAT ColorRGBA[4]) { + D3D10DeviceLock lock = LockContext(); + + auto rtv = static_cast<D3D11RenderTargetView*>(pRenderTargetView); + + if (!rtv) + return; + + auto view = rtv->GetImageView(); + auto color = ConvertColorValue(ColorRGBA, view->formatInfo()); + + EmitCs([ + cClearValue = color, + cImageView = std::move(view) + ] (DxvkContext* ctx) { + ctx->clearRenderTarget( + cImageView, + VK_IMAGE_ASPECT_COLOR_BIT, + cClearValue); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewUint( + ID3D11UnorderedAccessView* pUnorderedAccessView, + const UINT Values[4]) { + D3D10DeviceLock lock = LockContext(); + + auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView); + + if (!uav) + return; + + // Gather UAV format info. We'll use this to determine + // whether we need to create a temporary view or not. + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uav->GetDesc(&uavDesc); + + VkFormat uavFormat = m_parent->LookupFormat(uavDesc.Format, DXGI_VK_FORMAT_MODE_ANY).Format; + VkFormat rawFormat = m_parent->LookupFormat(uavDesc.Format, DXGI_VK_FORMAT_MODE_RAW).Format; + + if (uavFormat != rawFormat && rawFormat == VK_FORMAT_UNDEFINED) { + Logger::err(str::format("D3D11: ClearUnorderedAccessViewUint: No raw format found for ", uavFormat)); + return; + } + + // Set up clear color struct + VkClearValue clearValue; + clearValue.color.uint32[0] = Values[0]; + clearValue.color.uint32[1] = Values[1]; + clearValue.color.uint32[2] = Values[2]; + clearValue.color.uint32[3] = Values[3]; + + // This is the only packed format that has UAV support + if (uavFormat == VK_FORMAT_B10G11R11_UFLOAT_PACK32) { + clearValue.color.uint32[0] = ((Values[0] & 0x7FF) << 0) + | ((Values[1] & 0x7FF) << 11) + | ((Values[2] & 0x3FF) << 22); + } + + if (uav->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) { + // In case of raw and structured buffers as well as typed + // buffers that can be used for atomic operations, we can + // use the fast Vulkan buffer clear function. + Rc<DxvkBufferView> bufferView = uav->GetBufferView(); + + if (bufferView->info().format == VK_FORMAT_R32_UINT + || bufferView->info().format == VK_FORMAT_R32_SINT + || bufferView->info().format == VK_FORMAT_R32_SFLOAT) { + EmitCs([ + cClearValue = Values[0], + cDstSlice = bufferView->slice() + ] (DxvkContext* ctx) { + ctx->clearBuffer( + cDstSlice.buffer(), + cDstSlice.offset(), + cDstSlice.length(), + cClearValue); + }); + } else { + // Create a view with an integer format if necessary + if (uavFormat != rawFormat) { + DxvkBufferViewCreateInfo info = bufferView->info(); + info.format = rawFormat; + + bufferView = m_device->createBufferView( + bufferView->buffer(), info); + } + + EmitCs([ + cClearValue = clearValue, + cDstView = bufferView + ] (DxvkContext* ctx) { + ctx->clearBufferView( + cDstView, 0, + cDstView->elementCount(), + cClearValue.color); + }); + } + } else { + // Create a view with an integer format if necessary + Rc<DxvkImageView> imageView = uav->GetImageView(); + + if (uavFormat != rawFormat) { + DxvkImageViewCreateInfo info = imageView->info(); + info.format = rawFormat; + + imageView = m_device->createImageView( + imageView->image(), info); + } + + EmitCs([ + cClearValue = clearValue, + cDstView = imageView + ] (DxvkContext* ctx) { + ctx->clearImageView(cDstView, + VkOffset3D { 0, 0, 0 }, + cDstView->mipLevelExtent(0), + VK_IMAGE_ASPECT_COLOR_BIT, + cClearValue); + }); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewFloat( + ID3D11UnorderedAccessView* pUnorderedAccessView, + const FLOAT Values[4]) { + D3D10DeviceLock lock = LockContext(); + + auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView); + + if (!uav) + return; + + auto imgView = uav->GetImageView(); + auto bufView = uav->GetBufferView(); + + const DxvkFormatInfo* info = nullptr; + if (imgView != nullptr) info = imgView->formatInfo(); + if (bufView != nullptr) info = bufView->formatInfo(); + + if (!info || info->flags.any(DxvkFormatFlag::SampledSInt, DxvkFormatFlag::SampledUInt)) + return; + + VkClearValue clearValue; + clearValue.color.float32[0] = Values[0]; + clearValue.color.float32[1] = Values[1]; + clearValue.color.float32[2] = Values[2]; + clearValue.color.float32[3] = Values[3]; + + if (uav->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) { + EmitCs([ + cClearValue = clearValue, + cDstView = std::move(bufView) + ] (DxvkContext* ctx) { + ctx->clearBufferView( + cDstView, 0, + cDstView->elementCount(), + cClearValue.color); + }); + } else { + EmitCs([ + cClearValue = clearValue, + cDstView = std::move(imgView) + ] (DxvkContext* ctx) { + ctx->clearImageView(cDstView, + VkOffset3D { 0, 0, 0 }, + cDstView->mipLevelExtent(0), + VK_IMAGE_ASPECT_COLOR_BIT, + cClearValue); + }); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::ClearDepthStencilView( + ID3D11DepthStencilView* pDepthStencilView, + UINT ClearFlags, + FLOAT Depth, + UINT8 Stencil) { + D3D10DeviceLock lock = LockContext(); + + auto dsv = static_cast<D3D11DepthStencilView*>(pDepthStencilView); + + if (!dsv) + return; + + // Figure out which aspects to clear based on + // the image view properties and clear flags. + VkImageAspectFlags aspectMask = 0; + + if (ClearFlags & D3D11_CLEAR_DEPTH) + aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + + if (ClearFlags & D3D11_CLEAR_STENCIL) + aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + + aspectMask &= dsv->GetWritableAspectMask(); + + if (!aspectMask) + return; + + VkClearValue clearValue; + clearValue.depthStencil.depth = Depth; + clearValue.depthStencil.stencil = Stencil; + + EmitCs([ + cClearValue = clearValue, + cAspectMask = aspectMask, + cImageView = dsv->GetImageView() + ] (DxvkContext* ctx) { + ctx->clearRenderTarget( + cImageView, + cAspectMask, + cClearValue); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::ClearView( + ID3D11View* pView, + const FLOAT Color[4], + const D3D11_RECT* pRect, + UINT NumRects) { + D3D10DeviceLock lock = LockContext(); + + if (NumRects && !pRect) + return; + + // ID3D11View has no methods to query the exact type of + // the view, so we'll have to check each possible class + auto dsv = dynamic_cast<D3D11DepthStencilView*>(pView); + auto rtv = dynamic_cast<D3D11RenderTargetView*>(pView); + auto uav = dynamic_cast<D3D11UnorderedAccessView*>(pView); + auto vov = dynamic_cast<D3D11VideoProcessorOutputView*>(pView); + + // Retrieve underlying resource view + Rc<DxvkBufferView> bufView; + Rc<DxvkImageView> imgView; + + if (dsv != nullptr) + imgView = dsv->GetImageView(); + + if (rtv != nullptr) + imgView = rtv->GetImageView(); + + if (uav != nullptr) { + bufView = uav->GetBufferView(); + imgView = uav->GetImageView(); + } + + if (vov != nullptr) + imgView = vov->GetView(); + + // 3D views are unsupported + if (imgView != nullptr + && imgView->info().type == VK_IMAGE_VIEW_TYPE_3D) + return; + + // Query the view format. We'll have to convert + // the clear color based on the format's data type. + VkFormat format = VK_FORMAT_UNDEFINED; + + if (bufView != nullptr) + format = bufView->info().format; + + if (imgView != nullptr) + format = imgView->info().format; + + if (format == VK_FORMAT_UNDEFINED) + return; + + // We'll need the format info to determine the buffer + // element size, and we also need it for depth images. + const DxvkFormatInfo* formatInfo = imageFormatInfo(format); + + // Convert the clear color format. ClearView takes + // the clear value for integer formats as a set of + // integral floats, so we'll have to convert. + VkClearValue clearValue = ConvertColorValue(Color, formatInfo); + VkImageAspectFlags clearAspect = formatInfo->aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT); + + // Clear all the rectangles that are specified + for (uint32_t i = 0; i < NumRects || i < 1; i++) { + if (pRect) { + if (pRect[i].left >= pRect[i].right + || pRect[i].top >= pRect[i].bottom) + continue; + } + + if (bufView != nullptr) { + VkDeviceSize offset = 0; + VkDeviceSize length = bufView->info().rangeLength / formatInfo->elementSize; + + if (pRect) { + offset = pRect[i].left; + length = pRect[i].right - pRect[i].left; + } + + EmitCs([ + cBufferView = bufView, + cRangeOffset = offset, + cRangeLength = length, + cClearValue = clearValue + ] (DxvkContext* ctx) { + ctx->clearBufferView( + cBufferView, + cRangeOffset, + cRangeLength, + cClearValue.color); + }); + } + + if (imgView != nullptr) { + VkOffset3D offset = { 0, 0, 0 }; + VkExtent3D extent = imgView->mipLevelExtent(0); + + if (pRect) { + offset = { pRect[i].left, pRect[i].top, 0 }; + extent = { + uint32_t(pRect[i].right - pRect[i].left), + uint32_t(pRect[i].bottom - pRect[i].top), 1 }; + } + + EmitCs([ + cImageView = imgView, + cAreaOffset = offset, + cAreaExtent = extent, + cClearAspect = clearAspect, + cClearValue = clearValue + ] (DxvkContext* ctx) { + const VkImageUsageFlags rtUsage = + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + bool isFullSize = cImageView->mipLevelExtent(0) == cAreaExtent; + + if ((cImageView->info().usage & rtUsage) && isFullSize) { + ctx->clearRenderTarget( + cImageView, + cClearAspect, + cClearValue); + } else { + ctx->clearImageView( + cImageView, + cAreaOffset, + cAreaExtent, + cClearAspect, + cClearValue); + } + }); + } + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView* pShaderResourceView) { + D3D10DeviceLock lock = LockContext(); + + auto view = static_cast<D3D11ShaderResourceView*>(pShaderResourceView); + + if (!view || view->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) + return; + + D3D11_COMMON_RESOURCE_DESC resourceDesc = view->GetResourceDesc(); + + if (!(resourceDesc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS)) + return; + + EmitCs([cDstImageView = view->GetImageView()] + (DxvkContext* ctx) { + ctx->generateMipmaps(cDstImageView, VK_FILTER_LINEAR); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::UpdateSubresource( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch) { + UpdateSubresource1(pDstResource, + DstSubresource, pDstBox, pSrcData, + SrcRowPitch, SrcDepthPitch, 0); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::UpdateSubresource1( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch, + UINT CopyFlags) { + D3D10DeviceLock lock = LockContext(); + + if (!pDstResource) + return; + + // Filter out invalid copy flags + CopyFlags &= D3D11_COPY_NO_OVERWRITE | D3D11_COPY_DISCARD; + + // We need a different code path for buffers + D3D11_RESOURCE_DIMENSION resourceType; + pDstResource->GetType(&resourceType); + + if (resourceType == D3D11_RESOURCE_DIMENSION_BUFFER) { + const auto bufferResource = static_cast<D3D11Buffer*>(pDstResource); + const auto bufferSlice = bufferResource->GetBufferSlice(); + + VkDeviceSize offset = bufferSlice.offset(); + VkDeviceSize size = bufferSlice.length(); + + if (pDstBox != nullptr) { + offset = pDstBox->left; + size = pDstBox->right - pDstBox->left; + } + + if (!size || offset + size > bufferSlice.length()) + return; + + bool useMap = (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + && (size == bufferSlice.length() || CopyFlags); + + if (useMap) { + D3D11_MAP mapType = (CopyFlags & D3D11_COPY_NO_OVERWRITE) + ? D3D11_MAP_WRITE_NO_OVERWRITE + : D3D11_MAP_WRITE_DISCARD; + + D3D11_MAPPED_SUBRESOURCE mappedSr; + if (likely(useMap = SUCCEEDED(Map(pDstResource, 0, mapType, 0, &mappedSr)))) { + std::memcpy(reinterpret_cast<char*>(mappedSr.pData) + offset, pSrcData, size); + Unmap(pDstResource, 0); + } + } + + if (!useMap) { + DxvkDataSlice dataSlice = AllocUpdateBufferSlice(size); + std::memcpy(dataSlice.ptr(), pSrcData, size); + + EmitCs([ + cDataBuffer = std::move(dataSlice), + cBufferSlice = bufferSlice.subSlice(offset, size) + ] (DxvkContext* ctx) { + ctx->updateBuffer( + cBufferSlice.buffer(), + cBufferSlice.offset(), + cBufferSlice.length(), + cDataBuffer.ptr()); + }); + } + } else { + D3D11CommonTexture* dstTexture = GetCommonTexture(pDstResource); + + if (DstSubresource >= dstTexture->CountSubresources()) + return; + + VkFormat packedFormat = dstTexture->GetPackedFormat(); + + auto formatInfo = imageFormatInfo(packedFormat); + auto subresource = dstTexture->GetSubresourceFromIndex( + formatInfo->aspectMask, DstSubresource); + + VkExtent3D mipExtent = dstTexture->MipLevelExtent(subresource.mipLevel); + + VkOffset3D offset = { 0, 0, 0 }; + VkExtent3D extent = mipExtent; + + if (pDstBox != nullptr) { + if (pDstBox->left >= pDstBox->right + || pDstBox->top >= pDstBox->bottom + || pDstBox->front >= pDstBox->back) + return; // no-op, but legal + + offset.x = pDstBox->left; + offset.y = pDstBox->top; + offset.z = pDstBox->front; + + extent.width = pDstBox->right - pDstBox->left; + extent.height = pDstBox->bottom - pDstBox->top; + extent.depth = pDstBox->back - pDstBox->front; + } + + if (!util::isBlockAligned(offset, extent, formatInfo->blockSize, mipExtent)) { + Logger::err("D3D11: UpdateSubresource1: Unaligned region"); + return; + } + + auto stagingSlice = AllocStagingBuffer(util::computeImageDataSize(packedFormat, extent)); + + util::packImageData(stagingSlice.mapPtr(0), + pSrcData, SrcRowPitch, SrcDepthPitch, 0, 0, + dstTexture->GetVkImageType(), extent, 1, + formatInfo, formatInfo->aspectMask); + + UpdateImage(dstTexture, &subresource, + offset, extent, std::move(stagingSlice)); + } + } + + + HRESULT STDMETHODCALLTYPE D3D11DeviceContext::UpdateTileMappings( + ID3D11Resource* pTiledResource, + UINT NumTiledResourceRegions, + const D3D11_TILED_RESOURCE_COORDINATE* pTiledResourceRegionStartCoordinates, + const D3D11_TILE_REGION_SIZE* pTiledResourceRegionSizes, + ID3D11Buffer* pTilePool, + UINT NumRanges, + const UINT* pRangeFlags, + const UINT* pTilePoolStartOffsets, + const UINT* pRangeTileCounts, + UINT Flags) { + bool s_errorShown = false; + + if (std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::UpdateTileMappings: Not implemented"); + + return DXGI_ERROR_INVALID_CALL; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::UpdateTiles( + ID3D11Resource* pDestTiledResource, + const D3D11_TILED_RESOURCE_COORDINATE* pDestTileRegionStartCoordinate, + const D3D11_TILE_REGION_SIZE* pDestTileRegionSize, + const void* pSourceTileData, + UINT Flags) { + bool s_errorShown = false; + + if (std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::UpdateTiles: Not implemented"); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::SetResourceMinLOD( + ID3D11Resource* pResource, + FLOAT MinLOD) { + bool s_errorShown = false; + + if (std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::SetResourceMinLOD: Not implemented"); + } + + + FLOAT STDMETHODCALLTYPE D3D11DeviceContext::GetResourceMinLOD(ID3D11Resource* pResource) { + bool s_errorShown = false; + + if (std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::GetResourceMinLOD: Not implemented"); + + return 0.0f; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::ResolveSubresource( + ID3D11Resource* pDstResource, + UINT DstSubresource, + ID3D11Resource* pSrcResource, + UINT SrcSubresource, + DXGI_FORMAT Format) { + D3D10DeviceLock lock = LockContext(); + + bool isSameSubresource = pDstResource == pSrcResource + && DstSubresource == SrcSubresource; + + if (!pDstResource || !pSrcResource || isSameSubresource) + return; + + D3D11_RESOURCE_DIMENSION dstResourceType; + D3D11_RESOURCE_DIMENSION srcResourceType; + + pDstResource->GetType(&dstResourceType); + pSrcResource->GetType(&srcResourceType); + + if (dstResourceType != D3D11_RESOURCE_DIMENSION_TEXTURE2D + || srcResourceType != D3D11_RESOURCE_DIMENSION_TEXTURE2D) { + Logger::err(str::format( + "D3D11: ResolveSubresource: Incompatible resources", + "\n Dst resource type: ", dstResourceType, + "\n Src resource type: ", srcResourceType)); + return; + } + + auto dstTexture = static_cast<D3D11Texture2D*>(pDstResource); + auto srcTexture = static_cast<D3D11Texture2D*>(pSrcResource); + + D3D11_TEXTURE2D_DESC dstDesc; + D3D11_TEXTURE2D_DESC srcDesc; + + dstTexture->GetDesc(&dstDesc); + srcTexture->GetDesc(&srcDesc); + + if (dstDesc.SampleDesc.Count != 1) { + Logger::err(str::format( + "D3D11: ResolveSubresource: Invalid sample counts", + "\n Dst sample count: ", dstDesc.SampleDesc.Count, + "\n Src sample count: ", srcDesc.SampleDesc.Count)); + return; + } + + const D3D11CommonTexture* dstTextureInfo = GetCommonTexture(pDstResource); + const D3D11CommonTexture* srcTextureInfo = GetCommonTexture(pSrcResource); + + const DXGI_VK_FORMAT_INFO dstFormatInfo = m_parent->LookupFormat(dstDesc.Format, DXGI_VK_FORMAT_MODE_ANY); + const DXGI_VK_FORMAT_INFO srcFormatInfo = m_parent->LookupFormat(srcDesc.Format, DXGI_VK_FORMAT_MODE_ANY); + + auto dstVulkanFormatInfo = imageFormatInfo(dstFormatInfo.Format); + auto srcVulkanFormatInfo = imageFormatInfo(srcFormatInfo.Format); + + if (DstSubresource >= dstTextureInfo->CountSubresources() + || SrcSubresource >= srcTextureInfo->CountSubresources()) + return; + + const VkImageSubresource dstSubresource = + dstTextureInfo->GetSubresourceFromIndex( + dstVulkanFormatInfo->aspectMask, DstSubresource); + + const VkImageSubresource srcSubresource = + srcTextureInfo->GetSubresourceFromIndex( + srcVulkanFormatInfo->aspectMask, SrcSubresource); + + const VkImageSubresourceLayers dstSubresourceLayers = { + dstSubresource.aspectMask, + dstSubresource.mipLevel, + dstSubresource.arrayLayer, 1 }; + + const VkImageSubresourceLayers srcSubresourceLayers = { + srcSubresource.aspectMask, + srcSubresource.mipLevel, + srcSubresource.arrayLayer, 1 }; + + if (srcDesc.SampleDesc.Count == 1 || m_parent->GetOptions()->disableMsaa) { + EmitCs([ + cDstImage = dstTextureInfo->GetImage(), + cSrcImage = srcTextureInfo->GetImage(), + cDstLayers = dstSubresourceLayers, + cSrcLayers = srcSubresourceLayers + ] (DxvkContext* ctx) { + ctx->copyImage( + cDstImage, cDstLayers, VkOffset3D { 0, 0, 0 }, + cSrcImage, cSrcLayers, VkOffset3D { 0, 0, 0 }, + cDstImage->mipLevelExtent(cDstLayers.mipLevel)); + }); + } else { + const VkFormat format = m_parent->LookupFormat( + Format, DXGI_VK_FORMAT_MODE_ANY).Format; + + EmitCs([ + cDstImage = dstTextureInfo->GetImage(), + cSrcImage = srcTextureInfo->GetImage(), + cDstSubres = dstSubresourceLayers, + cSrcSubres = srcSubresourceLayers, + cFormat = format + ] (DxvkContext* ctx) { + VkImageResolve region; + region.srcSubresource = cSrcSubres; + region.srcOffset = VkOffset3D { 0, 0, 0 }; + region.dstSubresource = cDstSubres; + region.dstOffset = VkOffset3D { 0, 0, 0 }; + region.extent = cDstImage->mipLevelExtent(cDstSubres.mipLevel); + + ctx->resolveImage(cDstImage, cSrcImage, region, cFormat); + }); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DrawAuto() { + D3D10DeviceLock lock = LockContext(); + + D3D11Buffer* buffer = m_state.ia.vertexBuffers[0].buffer.ptr(); + + if (buffer == nullptr) + return; + + DxvkBufferSlice vtxBuf = buffer->GetBufferSlice(); + DxvkBufferSlice ctrBuf = buffer->GetSOCounter(); + + if (!ctrBuf.defined()) + return; + + EmitCs([=] (DxvkContext* ctx) { + ctx->drawIndirectXfb(ctrBuf, + vtxBuf.buffer()->getXfbVertexStride(), + vtxBuf.offset()); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::Draw( + UINT VertexCount, + UINT StartVertexLocation) { + D3D10DeviceLock lock = LockContext(); + + EmitCs([=] (DxvkContext* ctx) { + ctx->draw( + VertexCount, 1, + StartVertexLocation, 0); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexed( + UINT IndexCount, + UINT StartIndexLocation, + INT BaseVertexLocation) { + D3D10DeviceLock lock = LockContext(); + + EmitCs([=] (DxvkContext* ctx) { + ctx->drawIndexed( + IndexCount, 1, + StartIndexLocation, + BaseVertexLocation, 0); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstanced( + UINT VertexCountPerInstance, + UINT InstanceCount, + UINT StartVertexLocation, + UINT StartInstanceLocation) { + D3D10DeviceLock lock = LockContext(); + + EmitCs([=] (DxvkContext* ctx) { + ctx->draw( + VertexCountPerInstance, + InstanceCount, + StartVertexLocation, + StartInstanceLocation); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstanced( + UINT IndexCountPerInstance, + UINT InstanceCount, + UINT StartIndexLocation, + INT BaseVertexLocation, + UINT StartInstanceLocation) { + D3D10DeviceLock lock = LockContext(); + + EmitCs([=] (DxvkContext* ctx) { + ctx->drawIndexed( + IndexCountPerInstance, + InstanceCount, + StartIndexLocation, + BaseVertexLocation, + StartInstanceLocation); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstancedIndirect( + ID3D11Buffer* pBufferForArgs, + UINT AlignedByteOffsetForArgs) { + D3D10DeviceLock lock = LockContext(); + SetDrawBuffers(pBufferForArgs, nullptr); + + if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDrawIndexedIndirectCommand))) + return; + + // If possible, batch up multiple indirect draw calls of + // the same type into one single multiDrawIndirect call + auto cmdData = static_cast<D3D11CmdDrawIndirectData*>(m_cmdData); + auto stride = 0u; + + if (cmdData && cmdData->type == D3D11CmdType::DrawIndirectIndexed) + stride = GetIndirectCommandStride(cmdData, AlignedByteOffsetForArgs, sizeof(VkDrawIndexedIndirectCommand)); + + if (stride) { + cmdData->count += 1; + cmdData->stride = stride; + } else { + cmdData = EmitCsCmd<D3D11CmdDrawIndirectData>( + [] (DxvkContext* ctx, const D3D11CmdDrawIndirectData* data) { + ctx->drawIndexedIndirect(data->offset, data->count, data->stride); + }); + + cmdData->type = D3D11CmdType::DrawIndirectIndexed; + cmdData->offset = AlignedByteOffsetForArgs; + cmdData->count = 1; + cmdData->stride = 0; + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstancedIndirect( + ID3D11Buffer* pBufferForArgs, + UINT AlignedByteOffsetForArgs) { + D3D10DeviceLock lock = LockContext(); + SetDrawBuffers(pBufferForArgs, nullptr); + + if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDrawIndirectCommand))) + return; + + // If possible, batch up multiple indirect draw calls of + // the same type into one single multiDrawIndirect call + auto cmdData = static_cast<D3D11CmdDrawIndirectData*>(m_cmdData); + auto stride = 0u; + + if (cmdData && cmdData->type == D3D11CmdType::DrawIndirect) + stride = GetIndirectCommandStride(cmdData, AlignedByteOffsetForArgs, sizeof(VkDrawIndirectCommand)); + + if (stride) { + cmdData->count += 1; + cmdData->stride = stride; + } else { + cmdData = EmitCsCmd<D3D11CmdDrawIndirectData>( + [] (DxvkContext* ctx, const D3D11CmdDrawIndirectData* data) { + ctx->drawIndirect(data->offset, data->count, data->stride); + }); + + cmdData->type = D3D11CmdType::DrawIndirect; + cmdData->offset = AlignedByteOffsetForArgs; + cmdData->count = 1; + cmdData->stride = 0; + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::Dispatch( + UINT ThreadGroupCountX, + UINT ThreadGroupCountY, + UINT ThreadGroupCountZ) { + D3D10DeviceLock lock = LockContext(); + + EmitCs([=] (DxvkContext* ctx) { + ctx->dispatch( + ThreadGroupCountX, + ThreadGroupCountY, + ThreadGroupCountZ); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DispatchIndirect( + ID3D11Buffer* pBufferForArgs, + UINT AlignedByteOffsetForArgs) { + D3D10DeviceLock lock = LockContext(); + SetDrawBuffers(pBufferForArgs, nullptr); + + if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDispatchIndirectCommand))) + return; + + EmitCs([cOffset = AlignedByteOffsetForArgs] + (DxvkContext* ctx) { + ctx->dispatchIndirect(cOffset); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::IASetInputLayout(ID3D11InputLayout* pInputLayout) { + D3D10DeviceLock lock = LockContext(); + + auto inputLayout = static_cast<D3D11InputLayout*>(pInputLayout); + + if (m_state.ia.inputLayout != inputLayout) { + bool equal = false; + + // Some games (e.g. Grim Dawn) create lots and lots of + // identical input layouts, so we'll only apply the state + // if the input layouts has actually changed between calls. + if (m_state.ia.inputLayout != nullptr && inputLayout != nullptr) + equal = m_state.ia.inputLayout->Compare(inputLayout); + + m_state.ia.inputLayout = inputLayout; + + if (!equal) + ApplyInputLayout(); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology) { + D3D10DeviceLock lock = LockContext(); + + if (m_state.ia.primitiveTopology != Topology) { + m_state.ia.primitiveTopology = Topology; + ApplyPrimitiveTopology(); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::IASetVertexBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppVertexBuffers, + const UINT* pStrides, + const UINT* pOffsets) { + D3D10DeviceLock lock = LockContext(); + + for (uint32_t i = 0; i < NumBuffers; i++) { + auto newBuffer = static_cast<D3D11Buffer*>(ppVertexBuffers[i]); + bool needsUpdate = m_state.ia.vertexBuffers[StartSlot + i].buffer != newBuffer; + + if (needsUpdate) + m_state.ia.vertexBuffers[StartSlot + i].buffer = newBuffer; + + needsUpdate |= m_state.ia.vertexBuffers[StartSlot + i].offset != pOffsets[i] + || m_state.ia.vertexBuffers[StartSlot + i].stride != pStrides[i]; + + if (needsUpdate) { + m_state.ia.vertexBuffers[StartSlot + i].offset = pOffsets[i]; + m_state.ia.vertexBuffers[StartSlot + i].stride = pStrides[i]; + + BindVertexBuffer(StartSlot + i, newBuffer, pOffsets[i], pStrides[i]); + } + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::IASetIndexBuffer( + ID3D11Buffer* pIndexBuffer, + DXGI_FORMAT Format, + UINT Offset) { + D3D10DeviceLock lock = LockContext(); + + auto newBuffer = static_cast<D3D11Buffer*>(pIndexBuffer); + bool needsUpdate = m_state.ia.indexBuffer.buffer != newBuffer; + + if (needsUpdate) + m_state.ia.indexBuffer.buffer = newBuffer; + + needsUpdate |= m_state.ia.indexBuffer.offset != Offset + || m_state.ia.indexBuffer.format != Format; + + if (needsUpdate) { + m_state.ia.indexBuffer.offset = Offset; + m_state.ia.indexBuffer.format = Format; + + BindIndexBuffer(newBuffer, Offset, Format); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::IAGetInputLayout(ID3D11InputLayout** ppInputLayout) { + D3D10DeviceLock lock = LockContext(); + + *ppInputLayout = m_state.ia.inputLayout.ref(); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::IAGetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY* pTopology) { + D3D10DeviceLock lock = LockContext(); + + *pTopology = m_state.ia.primitiveTopology; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::IAGetVertexBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppVertexBuffers, + UINT* pStrides, + UINT* pOffsets) { + D3D10DeviceLock lock = LockContext(); + + for (uint32_t i = 0; i < NumBuffers; i++) { + const bool inRange = StartSlot + i < m_state.ia.vertexBuffers.size(); + + if (ppVertexBuffers != nullptr) { + ppVertexBuffers[i] = inRange + ? m_state.ia.vertexBuffers[StartSlot + i].buffer.ref() + : nullptr; + } + + if (pStrides != nullptr) { + pStrides[i] = inRange + ? m_state.ia.vertexBuffers[StartSlot + i].stride + : 0u; + } + + if (pOffsets != nullptr) { + pOffsets[i] = inRange + ? m_state.ia.vertexBuffers[StartSlot + i].offset + : 0u; + } + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::IAGetIndexBuffer( + ID3D11Buffer** ppIndexBuffer, + DXGI_FORMAT* pFormat, + UINT* pOffset) { + D3D10DeviceLock lock = LockContext(); + + if (ppIndexBuffer != nullptr) + *ppIndexBuffer = m_state.ia.indexBuffer.buffer.ref(); + + if (pFormat != nullptr) + *pFormat = m_state.ia.indexBuffer.format; + + if (pOffset != nullptr) + *pOffset = m_state.ia.indexBuffer.offset; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSSetShader( + ID3D11VertexShader* pVertexShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + auto shader = static_cast<D3D11VertexShader*>(pVertexShader); + + if (NumClassInstances != 0) + Logger::err("D3D11: Class instances not supported"); + + if (m_state.vs.shader != shader) { + m_state.vs.shader = shader; + + BindShader<DxbcProgramType::VertexShader>(GetCommonShader(shader)); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers<DxbcProgramType::VertexShader>( + m_state.vs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers1<DxbcProgramType::VertexShader>( + m_state.vs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + SetShaderResources<DxbcProgramType::VertexShader>( + m_state.vs.shaderResources, + StartSlot, NumViews, + ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + SetSamplers<DxbcProgramType::VertexShader>( + m_state.vs.samplers, + StartSlot, NumSamplers, + ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSGetShader( + ID3D11VertexShader** ppVertexShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + if (ppVertexShader != nullptr) + *ppVertexShader = m_state.vs.shader.ref(); + + if (pNumClassInstances != nullptr) + *pNumClassInstances = 0; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.vs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + nullptr, nullptr); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.vs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + GetShaderResources(m_state.vs.shaderResources, + StartSlot, NumViews, ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::VSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + GetSamplers(m_state.vs.samplers, + StartSlot, NumSamplers, ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSSetShader( + ID3D11HullShader* pHullShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + auto shader = static_cast<D3D11HullShader*>(pHullShader); + + if (NumClassInstances != 0) + Logger::err("D3D11: Class instances not supported"); + + if (m_state.hs.shader != shader) { + m_state.hs.shader = shader; + + BindShader<DxbcProgramType::HullShader>(GetCommonShader(shader)); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + SetShaderResources<DxbcProgramType::HullShader>( + m_state.hs.shaderResources, + StartSlot, NumViews, + ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers<DxbcProgramType::HullShader>( + m_state.hs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers1<DxbcProgramType::HullShader>( + m_state.hs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + SetSamplers<DxbcProgramType::HullShader>( + m_state.hs.samplers, + StartSlot, NumSamplers, + ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSGetShader( + ID3D11HullShader** ppHullShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + if (ppHullShader != nullptr) + *ppHullShader = m_state.hs.shader.ref(); + + if (pNumClassInstances != nullptr) + *pNumClassInstances = 0; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.hs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + nullptr, nullptr); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.hs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + GetShaderResources(m_state.hs.shaderResources, + StartSlot, NumViews, ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::HSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + GetSamplers(m_state.hs.samplers, + StartSlot, NumSamplers, ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSSetShader( + ID3D11DomainShader* pDomainShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + auto shader = static_cast<D3D11DomainShader*>(pDomainShader); + + if (NumClassInstances != 0) + Logger::err("D3D11: Class instances not supported"); + + if (m_state.ds.shader != shader) { + m_state.ds.shader = shader; + + BindShader<DxbcProgramType::DomainShader>(GetCommonShader(shader)); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + SetShaderResources<DxbcProgramType::DomainShader>( + m_state.ds.shaderResources, + StartSlot, NumViews, + ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers<DxbcProgramType::DomainShader>( + m_state.ds.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers1<DxbcProgramType::DomainShader>( + m_state.ds.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + SetSamplers<DxbcProgramType::DomainShader>( + m_state.ds.samplers, + StartSlot, NumSamplers, + ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSGetShader( + ID3D11DomainShader** ppDomainShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + if (ppDomainShader != nullptr) + *ppDomainShader = m_state.ds.shader.ref(); + + if (pNumClassInstances != nullptr) + *pNumClassInstances = 0; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.ds.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + nullptr, nullptr); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.ds.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + GetShaderResources(m_state.ds.shaderResources, + StartSlot, NumViews, ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::DSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + GetSamplers(m_state.ds.samplers, + StartSlot, NumSamplers, ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSSetShader( + ID3D11GeometryShader* pShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + auto shader = static_cast<D3D11GeometryShader*>(pShader); + + if (NumClassInstances != 0) + Logger::err("D3D11: Class instances not supported"); + + if (m_state.gs.shader != shader) { + m_state.gs.shader = shader; + + BindShader<DxbcProgramType::GeometryShader>(GetCommonShader(shader)); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers<DxbcProgramType::GeometryShader>( + m_state.gs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers1<DxbcProgramType::GeometryShader>( + m_state.gs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + SetShaderResources<DxbcProgramType::GeometryShader>( + m_state.gs.shaderResources, + StartSlot, NumViews, + ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + SetSamplers<DxbcProgramType::GeometryShader>( + m_state.gs.samplers, + StartSlot, NumSamplers, + ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSGetShader( + ID3D11GeometryShader** ppGeometryShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + if (ppGeometryShader != nullptr) + *ppGeometryShader = m_state.gs.shader.ref(); + + if (pNumClassInstances != nullptr) + *pNumClassInstances = 0; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.gs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + nullptr, nullptr); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.gs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + GetShaderResources(m_state.gs.shaderResources, + StartSlot, NumViews, ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + GetSamplers(m_state.gs.samplers, + StartSlot, NumSamplers, ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSSetShader( + ID3D11PixelShader* pPixelShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + auto shader = static_cast<D3D11PixelShader*>(pPixelShader); + + if (NumClassInstances != 0) + Logger::err("D3D11: Class instances not supported"); + + if (m_state.ps.shader != shader) { + m_state.ps.shader = shader; + + BindShader<DxbcProgramType::PixelShader>(GetCommonShader(shader)); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers<DxbcProgramType::PixelShader>( + m_state.ps.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers1<DxbcProgramType::PixelShader>( + m_state.ps.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + SetShaderResources<DxbcProgramType::PixelShader>( + m_state.ps.shaderResources, + StartSlot, NumViews, + ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + SetSamplers<DxbcProgramType::PixelShader>( + m_state.ps.samplers, + StartSlot, NumSamplers, + ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSGetShader( + ID3D11PixelShader** ppPixelShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + if (ppPixelShader != nullptr) + *ppPixelShader = m_state.ps.shader.ref(); + + if (pNumClassInstances != nullptr) + *pNumClassInstances = 0; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.ps.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + nullptr, nullptr); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.ps.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + GetShaderResources(m_state.ps.shaderResources, + StartSlot, NumViews, ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::PSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + GetSamplers(m_state.ps.samplers, + StartSlot, NumSamplers, ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSSetShader( + ID3D11ComputeShader* pComputeShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + auto shader = static_cast<D3D11ComputeShader*>(pComputeShader); + + if (NumClassInstances != 0) + Logger::err("D3D11: Class instances not supported"); + + if (m_state.cs.shader != shader) { + m_state.cs.shader = shader; + + BindShader<DxbcProgramType::ComputeShader>(GetCommonShader(shader)); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers<DxbcProgramType::ComputeShader>( + m_state.cs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + SetConstantBuffers1<DxbcProgramType::ComputeShader>( + m_state.cs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + SetShaderResources<DxbcProgramType::ComputeShader>( + m_state.cs.shaderResources, + StartSlot, NumViews, + ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + SetSamplers<DxbcProgramType::ComputeShader>( + m_state.cs.samplers, + StartSlot, NumSamplers, + ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSSetUnorderedAccessViews( + UINT StartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, + const UINT* pUAVInitialCounts) { + D3D10DeviceLock lock = LockContext(); + + if (TestRtvUavHazards(0, nullptr, NumUAVs, ppUnorderedAccessViews)) + return; + + // Unbind previously bound conflicting UAVs + uint32_t uavSlotId = computeUavBinding (DxbcProgramType::ComputeShader, 0); + uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::ComputeShader, 0); + + int32_t uavId = m_state.cs.uavMask.findNext(0); + + while (uavId >= 0) { + if (uint32_t(uavId) < StartSlot || uint32_t(uavId) >= StartSlot + NumUAVs) { + for (uint32_t i = 0; i < NumUAVs; i++) { + auto uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i]); + + if (CheckViewOverlap(uav, m_state.cs.unorderedAccessViews[uavId].ptr())) { + m_state.cs.unorderedAccessViews[uavId] = nullptr; + m_state.cs.uavMask.clr(uavId); + + BindUnorderedAccessView( + uavSlotId + uavId, nullptr, + ctrSlotId + uavId, ~0u); + } + } + + uavId = m_state.cs.uavMask.findNext(uavId + 1); + } else { + uavId = m_state.cs.uavMask.findNext(StartSlot + NumUAVs); + } + } + + // Actually bind the given UAVs + for (uint32_t i = 0; i < NumUAVs; i++) { + auto uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i]); + auto ctr = pUAVInitialCounts ? pUAVInitialCounts[i] : ~0u; + + if (m_state.cs.unorderedAccessViews[StartSlot + i] != uav || ctr != ~0u) { + m_state.cs.unorderedAccessViews[StartSlot + i] = uav; + m_state.cs.uavMask.set(StartSlot + i, uav != nullptr); + + BindUnorderedAccessView( + uavSlotId + StartSlot + i, uav, + ctrSlotId + StartSlot + i, ctr); + + ResolveCsSrvHazards(uav); + } + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSGetShader( + ID3D11ComputeShader** ppComputeShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances) { + D3D10DeviceLock lock = LockContext(); + + if (ppComputeShader != nullptr) + *ppComputeShader = m_state.cs.shader.ref(); + + if (pNumClassInstances != nullptr) + *pNumClassInstances = 0; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.cs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + nullptr, nullptr); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants) { + D3D10DeviceLock lock = LockContext(); + + GetConstantBuffers( + m_state.cs.constantBuffers, + StartSlot, NumBuffers, + ppConstantBuffers, + pFirstConstant, + pNumConstants); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews) { + D3D10DeviceLock lock = LockContext(); + + GetShaderResources(m_state.cs.shaderResources, + StartSlot, NumViews, ppShaderResourceViews); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers) { + D3D10DeviceLock lock = LockContext(); + + GetSamplers(m_state.cs.samplers, + StartSlot, NumSamplers, ppSamplers); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::CSGetUnorderedAccessViews( + UINT StartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView** ppUnorderedAccessViews) { + D3D10DeviceLock lock = LockContext(); + + for (uint32_t i = 0; i < NumUAVs; i++) { + ppUnorderedAccessViews[i] = StartSlot + i < m_state.cs.unorderedAccessViews.size() + ? m_state.cs.unorderedAccessViews[StartSlot + i].ref() + : nullptr; + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::OMSetRenderTargets( + UINT NumViews, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView) { + OMSetRenderTargetsAndUnorderedAccessViews( + NumViews, ppRenderTargetViews, pDepthStencilView, + NumViews, 0, nullptr, nullptr); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews( + UINT NumRTVs, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView, + UINT UAVStartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, + const UINT* pUAVInitialCounts) { + D3D10DeviceLock lock = LockContext(); + + if (TestRtvUavHazards(NumRTVs, ppRenderTargetViews, NumUAVs, ppUnorderedAccessViews)) + return; + + bool needsUpdate = false; + + if (likely(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)) { + // Native D3D11 does not change the render targets if + // the parameters passed to this method are invalid. + if (!ValidateRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView)) + return; + + for (uint32_t i = 0; i < m_state.om.renderTargetViews.size(); i++) { + auto rtv = i < NumRTVs + ? static_cast<D3D11RenderTargetView*>(ppRenderTargetViews[i]) + : nullptr; + + if (m_state.om.renderTargetViews[i] != rtv) { + m_state.om.renderTargetViews[i] = rtv; + needsUpdate = true; + ResolveOmSrvHazards(rtv); + + if (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS) + ResolveOmUavHazards(rtv); + } + } + + auto dsv = static_cast<D3D11DepthStencilView*>(pDepthStencilView); + + if (m_state.om.depthStencilView != dsv) { + m_state.om.depthStencilView = dsv; + needsUpdate = true; + ResolveOmSrvHazards(dsv); + } + + m_state.om.maxRtv = NumRTVs; + } + + if (unlikely(NumUAVs || m_state.om.maxUav)) { + uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0); + uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0); + + if (likely(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS)) { + uint32_t newMaxUav = NumUAVs ? UAVStartSlot + NumUAVs : 0; + uint32_t oldMaxUav = std::exchange(m_state.om.maxUav, newMaxUav); + + for (uint32_t i = 0; i < std::max(oldMaxUav, newMaxUav); i++) { + D3D11UnorderedAccessView* uav = nullptr; + uint32_t ctr = ~0u; + + if (i >= UAVStartSlot && i < UAVStartSlot + NumUAVs) { + uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i - UAVStartSlot]); + ctr = pUAVInitialCounts ? pUAVInitialCounts[i - UAVStartSlot] : ~0u; + } + + if (m_state.ps.unorderedAccessViews[i] != uav || ctr != ~0u) { + m_state.ps.unorderedAccessViews[i] = uav; + + BindUnorderedAccessView( + uavSlotId + i, uav, + ctrSlotId + i, ctr); + + ResolveOmSrvHazards(uav); + + if (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) + needsUpdate |= ResolveOmRtvHazards(uav); + } + } + } + } + + if (needsUpdate) + BindFramebuffer(); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::OMSetBlendState( + ID3D11BlendState* pBlendState, + const FLOAT BlendFactor[4], + UINT SampleMask) { + D3D10DeviceLock lock = LockContext(); + + auto blendState = static_cast<D3D11BlendState*>(pBlendState); + + if (m_state.om.cbState != blendState + || m_state.om.sampleMask != SampleMask) { + m_state.om.cbState = blendState; + m_state.om.sampleMask = SampleMask; + + ApplyBlendState(); + } + + if (BlendFactor != nullptr) { + for (uint32_t i = 0; i < 4; i++) + m_state.om.blendFactor[i] = BlendFactor[i]; + + ApplyBlendFactor(); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::OMSetDepthStencilState( + ID3D11DepthStencilState* pDepthStencilState, + UINT StencilRef) { + D3D10DeviceLock lock = LockContext(); + + auto depthStencilState = static_cast<D3D11DepthStencilState*>(pDepthStencilState); + + if (m_state.om.dsState != depthStencilState) { + m_state.om.dsState = depthStencilState; + ApplyDepthStencilState(); + } + + if (m_state.om.stencilRef != StencilRef) { + m_state.om.stencilRef = StencilRef; + ApplyStencilRef(); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::OMGetRenderTargets( + UINT NumViews, + ID3D11RenderTargetView** ppRenderTargetViews, + ID3D11DepthStencilView** ppDepthStencilView) { + D3D10DeviceLock lock = LockContext(); + + if (ppRenderTargetViews != nullptr) { + for (UINT i = 0; i < NumViews; i++) { + ppRenderTargetViews[i] = i < m_state.om.renderTargetViews.size() + ? m_state.om.renderTargetViews[i].ref() + : nullptr; + } + } + + if (ppDepthStencilView != nullptr) + *ppDepthStencilView = m_state.om.depthStencilView.ref(); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::OMGetRenderTargetsAndUnorderedAccessViews( + UINT NumRTVs, + ID3D11RenderTargetView** ppRenderTargetViews, + ID3D11DepthStencilView** ppDepthStencilView, + UINT UAVStartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView** ppUnorderedAccessViews) { + OMGetRenderTargets(NumRTVs, ppRenderTargetViews, ppDepthStencilView); + + D3D10DeviceLock lock = LockContext(); + + if (ppUnorderedAccessViews != nullptr) { + for (UINT i = 0; i < NumUAVs; i++) { + ppUnorderedAccessViews[i] = UAVStartSlot + i < m_state.ps.unorderedAccessViews.size() + ? m_state.ps.unorderedAccessViews[UAVStartSlot + i].ref() + : nullptr; + } + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::OMGetBlendState( + ID3D11BlendState** ppBlendState, + FLOAT BlendFactor[4], + UINT* pSampleMask) { + D3D10DeviceLock lock = LockContext(); + + if (ppBlendState != nullptr) + *ppBlendState = ref(m_state.om.cbState); + + if (BlendFactor != nullptr) + std::memcpy(BlendFactor, m_state.om.blendFactor, sizeof(FLOAT) * 4); + + if (pSampleMask != nullptr) + *pSampleMask = m_state.om.sampleMask; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::OMGetDepthStencilState( + ID3D11DepthStencilState** ppDepthStencilState, + UINT* pStencilRef) { + D3D10DeviceLock lock = LockContext(); + + if (ppDepthStencilState != nullptr) + *ppDepthStencilState = ref(m_state.om.dsState); + + if (pStencilRef != nullptr) + *pStencilRef = m_state.om.stencilRef; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::RSSetState(ID3D11RasterizerState* pRasterizerState) { + D3D10DeviceLock lock = LockContext(); + + auto rasterizerState = static_cast<D3D11RasterizerState*>(pRasterizerState); + + bool currScissorEnable = m_state.rs.state != nullptr + ? m_state.rs.state->Desc()->ScissorEnable + : false; + + bool nextScissorEnable = rasterizerState != nullptr + ? rasterizerState->Desc()->ScissorEnable + : false; + + if (m_state.rs.state != rasterizerState) { + m_state.rs.state = rasterizerState; + + // In D3D11, the rasterizer state defines whether the + // scissor test is enabled, so we have to update the + // scissor rectangles as well. + ApplyRasterizerState(); + + if (currScissorEnable != nextScissorEnable) + ApplyViewportState(); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::RSSetViewports( + UINT NumViewports, + const D3D11_VIEWPORT* pViewports) { + D3D10DeviceLock lock = LockContext(); + + if (unlikely(NumViewports > m_state.rs.viewports.size())) + return; + + bool dirty = m_state.rs.numViewports != NumViewports; + m_state.rs.numViewports = NumViewports; + + for (uint32_t i = 0; i < NumViewports; i++) { + const D3D11_VIEWPORT& vp = m_state.rs.viewports[i]; + + dirty |= vp.TopLeftX != pViewports[i].TopLeftX + || vp.TopLeftY != pViewports[i].TopLeftY + || vp.Width != pViewports[i].Width + || vp.Height != pViewports[i].Height + || vp.MinDepth != pViewports[i].MinDepth + || vp.MaxDepth != pViewports[i].MaxDepth; + + m_state.rs.viewports[i] = pViewports[i]; + } + + if (dirty) + ApplyViewportState(); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::RSSetScissorRects( + UINT NumRects, + const D3D11_RECT* pRects) { + D3D10DeviceLock lock = LockContext(); + + if (unlikely(NumRects > m_state.rs.scissors.size())) + return; + + bool dirty = m_state.rs.numScissors != NumRects; + m_state.rs.numScissors = NumRects; + + for (uint32_t i = 0; i < NumRects; i++) { + if (pRects[i].bottom >= pRects[i].top + && pRects[i].right >= pRects[i].left) { + const D3D11_RECT& sr = m_state.rs.scissors[i]; + + dirty |= sr.top != pRects[i].top + || sr.left != pRects[i].left + || sr.bottom != pRects[i].bottom + || sr.right != pRects[i].right; + + m_state.rs.scissors[i] = pRects[i]; + } + } + + if (m_state.rs.state != nullptr && dirty) { + D3D11_RASTERIZER_DESC rsDesc; + m_state.rs.state->GetDesc(&rsDesc); + + if (rsDesc.ScissorEnable) + ApplyViewportState(); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::RSGetState(ID3D11RasterizerState** ppRasterizerState) { + D3D10DeviceLock lock = LockContext(); + + if (ppRasterizerState != nullptr) + *ppRasterizerState = ref(m_state.rs.state); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::RSGetViewports( + UINT* pNumViewports, + D3D11_VIEWPORT* pViewports) { + D3D10DeviceLock lock = LockContext(); + uint32_t numWritten = m_state.rs.numViewports; + + if (pViewports) { + numWritten = std::min(numWritten, *pNumViewports); + + for (uint32_t i = 0; i < *pNumViewports; i++) { + if (i < m_state.rs.numViewports) { + pViewports[i] = m_state.rs.viewports[i]; + } else { + pViewports[i].TopLeftX = 0.0f; + pViewports[i].TopLeftY = 0.0f; + pViewports[i].Width = 0.0f; + pViewports[i].Height = 0.0f; + pViewports[i].MinDepth = 0.0f; + pViewports[i].MaxDepth = 0.0f; + } + } + } + + *pNumViewports = numWritten; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::RSGetScissorRects( + UINT* pNumRects, + D3D11_RECT* pRects) { + D3D10DeviceLock lock = LockContext(); + uint32_t numWritten = m_state.rs.numScissors; + + if (pRects) { + numWritten = std::min(numWritten, *pNumRects); + + for (uint32_t i = 0; i < *pNumRects; i++) { + if (i < m_state.rs.numScissors) { + pRects[i] = m_state.rs.scissors[i]; + } else { + pRects[i].left = 0; + pRects[i].top = 0; + pRects[i].right = 0; + pRects[i].bottom = 0; + } + } + } + + *pNumRects = m_state.rs.numScissors; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::SOSetTargets( + UINT NumBuffers, + ID3D11Buffer* const* ppSOTargets, + const UINT* pOffsets) { + D3D10DeviceLock lock = LockContext(); + + for (uint32_t i = 0; i < NumBuffers; i++) { + D3D11Buffer* buffer = static_cast<D3D11Buffer*>(ppSOTargets[i]); + UINT offset = pOffsets != nullptr ? pOffsets[i] : 0; + + m_state.so.targets[i].buffer = buffer; + m_state.so.targets[i].offset = offset; + } + + for (uint32_t i = NumBuffers; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) { + m_state.so.targets[i].buffer = nullptr; + m_state.so.targets[i].offset = 0; + } + + for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) { + BindXfbBuffer(i, + m_state.so.targets[i].buffer.ptr(), + m_state.so.targets[i].offset); + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::SOGetTargets( + UINT NumBuffers, + ID3D11Buffer** ppSOTargets) { + D3D10DeviceLock lock = LockContext(); + + for (uint32_t i = 0; i < NumBuffers; i++) { + ppSOTargets[i] = i < m_state.so.targets.size() + ? m_state.so.targets[i].buffer.ref() + : nullptr; + } + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::SOGetTargetsWithOffsets( + UINT NumBuffers, + ID3D11Buffer** ppSOTargets, + UINT* pOffsets) { + D3D10DeviceLock lock = LockContext(); + + for (uint32_t i = 0; i < NumBuffers; i++) { + const bool inRange = i < m_state.so.targets.size(); + + if (ppSOTargets != nullptr) { + ppSOTargets[i] = inRange + ? m_state.so.targets[i].buffer.ref() + : nullptr; + } + + if (pOffsets != nullptr) { + pOffsets[i] = inRange + ? m_state.so.targets[i].offset + : 0u; + } + } + } + + + BOOL STDMETHODCALLTYPE D3D11DeviceContext::IsAnnotationEnabled() { + return m_device->instance()->extensions().extDebugUtils; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::SetMarkerInt( + LPCWSTR pLabel, + INT Data) { + // Not implemented in the backend, ignore + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::BeginEventInt( + LPCWSTR pLabel, + INT Data) { + // Not implemented in the backend, ignore + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::EndEvent() { + // Not implemented in the backend, ignore + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::GetHardwareProtectionState( + BOOL* pHwProtectionEnable) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::GetHardwareProtectionState: Not implemented"); + + if (pHwProtectionEnable) + *pHwProtectionEnable = FALSE; + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::SetHardwareProtectionState( + BOOL HwProtectionEnable) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11DeviceContext::SetHardwareProtectionState: Not implemented"); + } + + + void STDMETHODCALLTYPE D3D11DeviceContext::TransitionSurfaceLayout( + IDXGIVkInteropSurface* pSurface, + const VkImageSubresourceRange* pSubresources, + VkImageLayout OldLayout, + VkImageLayout NewLayout) { + D3D10DeviceLock lock = LockContext(); + + // Get the underlying D3D11 resource + Com<ID3D11Resource> resource; + + pSurface->QueryInterface(__uuidof(ID3D11Resource), + reinterpret_cast<void**>(&resource)); + + // Get the texture from that resource + D3D11CommonTexture* texture = GetCommonTexture(resource.ptr()); + + EmitCs([ + cImage = texture->GetImage(), + cSubresources = *pSubresources, + cOldLayout = OldLayout, + cNewLayout = NewLayout + ] (DxvkContext* ctx) { + ctx->transformImage( + cImage, cSubresources, + cOldLayout, cNewLayout); + }); + } + + + void D3D11DeviceContext::ApplyInputLayout() { + auto inputLayout = m_state.ia.inputLayout.prvRef(); + + if (likely(inputLayout != nullptr)) { + EmitCs([ + cInputLayout = std::move(inputLayout) + ] (DxvkContext* ctx) { + cInputLayout->BindToContext(ctx); + }); + } else { + EmitCs([] (DxvkContext* ctx) { + ctx->setInputLayout(0, nullptr, 0, nullptr); + }); + } + } + + + void D3D11DeviceContext::ApplyPrimitiveTopology() { + D3D11_PRIMITIVE_TOPOLOGY topology = m_state.ia.primitiveTopology; + DxvkInputAssemblyState iaState = { }; + + if (topology <= D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ) { + static const std::array<DxvkInputAssemblyState, 14> s_iaStates = {{ + { VK_PRIMITIVE_TOPOLOGY_MAX_ENUM, VK_FALSE, 0 }, + { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_FALSE, 0 }, + { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_FALSE, 0 }, + { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_TRUE, 0 }, + { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE, 0 }, + { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_TRUE, 0 }, + { }, { }, { }, { }, // Random gap that exists for no reason + { VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, VK_FALSE, 0 }, + { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, VK_TRUE, 0 }, + { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, VK_FALSE, 0 }, + { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, VK_TRUE, 0 }, + }}; + + iaState = s_iaStates[uint32_t(topology)]; + } else if (topology >= D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + && topology <= D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST) { + // The number of control points per patch can be inferred from the enum value in D3D11 + uint32_t vertexCount = uint32_t(topology - D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + 1); + iaState = { VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE, vertexCount }; + } + + EmitCs([iaState] (DxvkContext* ctx) { + ctx->setInputAssemblyState(iaState); + }); + } + + + void D3D11DeviceContext::ApplyBlendState() { + if (m_state.om.cbState != nullptr) { + EmitCs([ + cBlendState = m_state.om.cbState, + cSampleMask = m_state.om.sampleMask + ] (DxvkContext* ctx) { + cBlendState->BindToContext(ctx, cSampleMask); + }); + } else { + EmitCs([ + cSampleMask = m_state.om.sampleMask + ] (DxvkContext* ctx) { + DxvkBlendMode cbState; + DxvkLogicOpState loState; + DxvkMultisampleState msState; + InitDefaultBlendState(&cbState, &loState, &msState, cSampleMask); + + for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + ctx->setBlendMode(i, cbState); + + ctx->setLogicOpState(loState); + ctx->setMultisampleState(msState); + }); + } + } + + + void D3D11DeviceContext::ApplyBlendFactor() { + EmitCs([ + cBlendConstants = DxvkBlendConstants { + m_state.om.blendFactor[0], m_state.om.blendFactor[1], + m_state.om.blendFactor[2], m_state.om.blendFactor[3] } + ] (DxvkContext* ctx) { + ctx->setBlendConstants(cBlendConstants); + }); + } + + + void D3D11DeviceContext::ApplyDepthStencilState() { + if (m_state.om.dsState != nullptr) { + EmitCs([ + cDepthStencilState = m_state.om.dsState + ] (DxvkContext* ctx) { + cDepthStencilState->BindToContext(ctx); + }); + } else { + EmitCs([] (DxvkContext* ctx) { + DxvkDepthStencilState dsState; + InitDefaultDepthStencilState(&dsState); + + ctx->setDepthStencilState(dsState); + }); + } + } + + + void D3D11DeviceContext::ApplyStencilRef() { + EmitCs([ + cStencilRef = m_state.om.stencilRef + ] (DxvkContext* ctx) { + ctx->setStencilReference(cStencilRef); + }); + } + + + void D3D11DeviceContext::ApplyRasterizerState() { + if (m_state.rs.state != nullptr) { + EmitCs([ + cRasterizerState = m_state.rs.state + ] (DxvkContext* ctx) { + cRasterizerState->BindToContext(ctx); + }); + } else { + EmitCs([] (DxvkContext* ctx) { + DxvkRasterizerState rsState; + InitDefaultRasterizerState(&rsState); + + ctx->setRasterizerState(rsState); + }); + } + } + + + void D3D11DeviceContext::ApplyViewportState() { + std::array<VkViewport, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> viewports; + std::array<VkRect2D, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> scissors; + + // The backend can't handle a viewport count of zero, + // so we should at least specify one empty viewport + uint32_t viewportCount = m_state.rs.numViewports; + + if (unlikely(!viewportCount)) { + viewportCount = 1; + viewports[0] = VkViewport(); + scissors [0] = VkRect2D(); + } + + // D3D11's coordinate system has its origin in the bottom left, + // but the viewport coordinates are aligned to the top-left + // corner so we can get away with flipping the viewport. + for (uint32_t i = 0; i < m_state.rs.numViewports; i++) { + const D3D11_VIEWPORT& vp = m_state.rs.viewports[i]; + + viewports[i] = VkViewport { + vp.TopLeftX, vp.Height + vp.TopLeftY, + vp.Width, -vp.Height, + vp.MinDepth, vp.MaxDepth, + }; + } + + // Scissor rectangles. Vulkan does not provide an easy way + // to disable the scissor test, so we'll have to set scissor + // rects that are at least as large as the framebuffer. + bool enableScissorTest = false; + + if (m_state.rs.state != nullptr) { + D3D11_RASTERIZER_DESC rsDesc; + m_state.rs.state->GetDesc(&rsDesc); + enableScissorTest = rsDesc.ScissorEnable; + } + + for (uint32_t i = 0; i < m_state.rs.numViewports; i++) { + if (!enableScissorTest) { + scissors[i] = VkRect2D { + VkOffset2D { 0, 0 }, + VkExtent2D { + D3D11_VIEWPORT_BOUNDS_MAX, + D3D11_VIEWPORT_BOUNDS_MAX } }; + } else if (i >= m_state.rs.numScissors) { + scissors[i] = VkRect2D { + VkOffset2D { 0, 0 }, + VkExtent2D { 0, 0 } }; + } else { + D3D11_RECT sr = m_state.rs.scissors[i]; + + VkOffset2D srPosA; + srPosA.x = std::max<int32_t>(0, sr.left); + srPosA.y = std::max<int32_t>(0, sr.top); + + VkOffset2D srPosB; + srPosB.x = std::max<int32_t>(srPosA.x, sr.right); + srPosB.y = std::max<int32_t>(srPosA.y, sr.bottom); + + VkExtent2D srSize; + srSize.width = uint32_t(srPosB.x - srPosA.x); + srSize.height = uint32_t(srPosB.y - srPosA.y); + + scissors[i] = VkRect2D { srPosA, srSize }; + } + } + + if (likely(viewportCount == 1)) { + EmitCs([ + cViewport = viewports[0], + cScissor = scissors[0] + ] (DxvkContext* ctx) { + ctx->setViewports(1, + &cViewport, + &cScissor); + }); + } else { + EmitCs([ + cViewportCount = viewportCount, + cViewports = viewports, + cScissors = scissors + ] (DxvkContext* ctx) { + ctx->setViewports( + cViewportCount, + cViewports.data(), + cScissors.data()); + }); + } + } + + + template<DxbcProgramType ShaderStage> + void D3D11DeviceContext::BindShader( + const D3D11CommonShader* pShaderModule) { + // Bind the shader and the ICB at once + EmitCs([ + cSlice = pShaderModule != nullptr + && pShaderModule->GetIcb() != nullptr + ? DxvkBufferSlice(pShaderModule->GetIcb()) + : DxvkBufferSlice(), + cShader = pShaderModule != nullptr + ? pShaderModule->GetShader() + : nullptr + ] (DxvkContext* ctx) { + VkShaderStageFlagBits stage = GetShaderStage(ShaderStage); + + uint32_t slotId = computeConstantBufferBinding(ShaderStage, + D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT); + + ctx->bindShader (stage, cShader); + ctx->bindResourceBuffer(slotId, cSlice); + }); + } + + + void D3D11DeviceContext::BindFramebuffer() { + DxvkRenderTargets attachments; + + // D3D11 doesn't have the concept of a framebuffer object, + // so we'll just create a new one every time the render + // target bindings are updated. Set up the attachments. + for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) { + if (m_state.om.renderTargetViews[i] != nullptr) { + attachments.color[i] = { + m_state.om.renderTargetViews[i]->GetImageView(), + m_state.om.renderTargetViews[i]->GetRenderLayout() }; + } + } + + if (m_state.om.depthStencilView != nullptr) { + attachments.depth = { + m_state.om.depthStencilView->GetImageView(), + m_state.om.depthStencilView->GetRenderLayout() }; + } + + // Create and bind the framebuffer object to the context + EmitCs([ + cAttachments = std::move(attachments) + ] (DxvkContext* ctx) { + ctx->bindRenderTargets(cAttachments); + }); + } + + + void D3D11DeviceContext::BindDrawBuffers( + D3D11Buffer* pBufferForArgs, + D3D11Buffer* pBufferForCount) { + EmitCs([ + cArgBuffer = pBufferForArgs ? pBufferForArgs->GetBufferSlice() : DxvkBufferSlice(), + cCntBuffer = pBufferForCount ? pBufferForCount->GetBufferSlice() : DxvkBufferSlice() + ] (DxvkContext* ctx) { + ctx->bindDrawBuffers(cArgBuffer, cCntBuffer); + }); + } + + + void D3D11DeviceContext::BindVertexBuffer( + UINT Slot, + D3D11Buffer* pBuffer, + UINT Offset, + UINT Stride) { + EmitCs([ + cSlotId = Slot, + cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(), + cStride = Stride + ] (DxvkContext* ctx) { + ctx->bindVertexBuffer(cSlotId, cBufferSlice, cStride); + }); + } + + + void D3D11DeviceContext::BindIndexBuffer( + D3D11Buffer* pBuffer, + UINT Offset, + DXGI_FORMAT Format) { + VkIndexType indexType = Format == DXGI_FORMAT_R16_UINT + ? VK_INDEX_TYPE_UINT16 + : VK_INDEX_TYPE_UINT32; + + EmitCs([ + cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(), + cIndexType = indexType + ] (DxvkContext* ctx) { + ctx->bindIndexBuffer(cBufferSlice, cIndexType); + }); + } + + + void D3D11DeviceContext::BindXfbBuffer( + UINT Slot, + D3D11Buffer* pBuffer, + UINT Offset) { + DxvkBufferSlice bufferSlice; + DxvkBufferSlice counterSlice; + + if (pBuffer != nullptr) { + bufferSlice = pBuffer->GetBufferSlice(); + counterSlice = pBuffer->GetSOCounter(); + } + + EmitCs([ + cSlotId = Slot, + cOffset = Offset, + cBufferSlice = bufferSlice, + cCounterSlice = counterSlice + ] (DxvkContext* ctx) { + if (cCounterSlice.defined() && cOffset != ~0u) { + ctx->updateBuffer( + cCounterSlice.buffer(), + cCounterSlice.offset(), + sizeof(cOffset), + &cOffset); + } + + ctx->bindXfbBuffer(cSlotId, cBufferSlice, cCounterSlice); + }); + } + + + void D3D11DeviceContext::BindConstantBuffer( + UINT Slot, + D3D11Buffer* pBuffer, + UINT Offset, + UINT Length) { + EmitCs([ + cSlotId = Slot, + cBufferSlice = Length ? pBuffer->GetBufferSlice(16 * Offset, 16 * Length) : DxvkBufferSlice() + ] (DxvkContext* ctx) { + ctx->bindResourceBuffer(cSlotId, cBufferSlice); + }); + } + + + void D3D11DeviceContext::BindSampler( + UINT Slot, + D3D11SamplerState* pSampler) { + EmitCs([ + cSlotId = Slot, + cSampler = pSampler != nullptr ? pSampler->GetDXVKSampler() : nullptr + ] (DxvkContext* ctx) { + ctx->bindResourceSampler(cSlotId, cSampler); + }); + } + + + void D3D11DeviceContext::BindShaderResource( + UINT Slot, + D3D11ShaderResourceView* pResource) { + EmitCs([ + cSlotId = Slot, + cImageView = pResource != nullptr ? pResource->GetImageView() : nullptr, + cBufferView = pResource != nullptr ? pResource->GetBufferView() : nullptr + ] (DxvkContext* ctx) { + ctx->bindResourceView(cSlotId, cImageView, cBufferView); + }); + } + + + void D3D11DeviceContext::BindUnorderedAccessView( + UINT UavSlot, + D3D11UnorderedAccessView* pUav, + UINT CtrSlot, + UINT Counter) { + EmitCs([ + cUavSlotId = UavSlot, + cCtrSlotId = CtrSlot, + cImageView = pUav != nullptr ? pUav->GetImageView() : nullptr, + cBufferView = pUav != nullptr ? pUav->GetBufferView() : nullptr, + cCounterSlice = pUav != nullptr ? pUav->GetCounterSlice() : DxvkBufferSlice(), + cCounterValue = Counter + ] (DxvkContext* ctx) { + if (cCounterSlice.defined() && cCounterValue != ~0u) { + ctx->updateBuffer( + cCounterSlice.buffer(), + cCounterSlice.offset(), + sizeof(uint32_t), + &cCounterValue); + } + + ctx->bindResourceView (cUavSlotId, cImageView, cBufferView); + ctx->bindResourceBuffer (cCtrSlotId, cCounterSlice); + }); + } + + + void D3D11DeviceContext::CopyBuffer( + D3D11Buffer* pDstBuffer, + VkDeviceSize DstOffset, + D3D11Buffer* pSrcBuffer, + VkDeviceSize SrcOffset, + VkDeviceSize ByteCount) { + // Clamp copy region to prevent out-of-bounds access + VkDeviceSize dstLength = pDstBuffer->Desc()->ByteWidth; + VkDeviceSize srcLength = pSrcBuffer->Desc()->ByteWidth; + + if (SrcOffset >= srcLength || DstOffset >= dstLength || !ByteCount) + return; + + ByteCount = std::min(dstLength - DstOffset, ByteCount); + ByteCount = std::min(srcLength - SrcOffset, ByteCount); + + EmitCs([ + cDstBuffer = pDstBuffer->GetBufferSlice(DstOffset, ByteCount), + cSrcBuffer = pSrcBuffer->GetBufferSlice(SrcOffset, ByteCount) + ] (DxvkContext* ctx) { + if (cDstBuffer.buffer() != cSrcBuffer.buffer()) { + ctx->copyBuffer( + cDstBuffer.buffer(), + cDstBuffer.offset(), + cSrcBuffer.buffer(), + cSrcBuffer.offset(), + cSrcBuffer.length()); + } else { + ctx->copyBufferRegion( + cDstBuffer.buffer(), + cDstBuffer.offset(), + cSrcBuffer.offset(), + cSrcBuffer.length()); + } + }); + } + + + void D3D11DeviceContext::CopyImage( + D3D11CommonTexture* pDstTexture, + const VkImageSubresourceLayers* pDstLayers, + VkOffset3D DstOffset, + D3D11CommonTexture* pSrcTexture, + const VkImageSubresourceLayers* pSrcLayers, + VkOffset3D SrcOffset, + VkExtent3D SrcExtent) { + // Image formats must be size-compatible + auto dstFormatInfo = imageFormatInfo(pDstTexture->GetPackedFormat()); + auto srcFormatInfo = imageFormatInfo(pSrcTexture->GetPackedFormat()); + + if (dstFormatInfo->elementSize != srcFormatInfo->elementSize) { + Logger::err("D3D11: CopyImage: Incompatible texel size"); + return; + } + + // Sample counts must match + if (pDstTexture->Desc()->SampleDesc.Count != pSrcTexture->Desc()->SampleDesc.Count) { + Logger::err("D3D11: CopyImage: Incompatible sample count"); + return; + } + + // Obviously, the copy region must not be empty + VkExtent3D dstMipExtent = pDstTexture->MipLevelExtent(pDstLayers->mipLevel); + VkExtent3D srcMipExtent = pSrcTexture->MipLevelExtent(pSrcLayers->mipLevel); + + if (uint32_t(DstOffset.x) >= dstMipExtent.width + || uint32_t(DstOffset.y) >= dstMipExtent.height + || uint32_t(DstOffset.z) >= dstMipExtent.depth) + return; + + if (uint32_t(SrcOffset.x) >= srcMipExtent.width + || uint32_t(SrcOffset.y) >= srcMipExtent.height + || uint32_t(SrcOffset.z) >= srcMipExtent.depth) + return; + + // Don't perform the copy if the offsets aren't block-aligned + if (!util::isBlockAligned(SrcOffset, srcFormatInfo->blockSize) + || !util::isBlockAligned(DstOffset, dstFormatInfo->blockSize)) { + Logger::err(str::format("D3D11: CopyImage: Unaligned block offset")); + return; + } + + // Clamp the image region in order to avoid out-of-bounds access + VkExtent3D blockCount = util::computeBlockCount(SrcExtent, srcFormatInfo->blockSize); + VkExtent3D dstBlockCount = util::computeMaxBlockCount(DstOffset, dstMipExtent, dstFormatInfo->blockSize); + VkExtent3D srcBlockCount = util::computeMaxBlockCount(SrcOffset, srcMipExtent, srcFormatInfo->blockSize); + + blockCount = util::minExtent3D(blockCount, dstBlockCount); + blockCount = util::minExtent3D(blockCount, srcBlockCount); + + SrcExtent = util::computeBlockExtent(blockCount, srcFormatInfo->blockSize); + SrcExtent = util::snapExtent3D(SrcOffset, SrcExtent, srcMipExtent); + + if (!SrcExtent.width || !SrcExtent.height || !SrcExtent.depth) + return; + + // While copying between 2D and 3D images is allowed in CopySubresourceRegion, + // copying more than one slice at a time is not suppoted. Layer counts are 1. + if ((pDstTexture->GetVkImageType() == VK_IMAGE_TYPE_3D) + != (pSrcTexture->GetVkImageType() == VK_IMAGE_TYPE_3D)) + SrcExtent.depth = 1; + + // Certain types of copies require us to pass the destination extent to + // the backend. This may be different when copying between compressed + // and uncompressed image formats. + VkExtent3D dstExtent = util::computeBlockExtent(blockCount, dstFormatInfo->blockSize); + dstExtent = util::snapExtent3D(DstOffset, dstExtent, dstMipExtent); + + // It is possible for any of the given images to be a staging image with + // no actual image, so we need to account for all possibilities here. + bool dstIsImage = pDstTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING; + bool srcIsImage = pSrcTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING; + + if (dstIsImage && srcIsImage) { + EmitCs([ + cDstImage = pDstTexture->GetImage(), + cSrcImage = pSrcTexture->GetImage(), + cDstLayers = *pDstLayers, + cSrcLayers = *pSrcLayers, + cDstOffset = DstOffset, + cSrcOffset = SrcOffset, + cExtent = SrcExtent + ] (DxvkContext* ctx) { + // CopyResource can only copy between different images, and + // CopySubresourceRegion can only copy data from one single + // subresource at a time, so this check is safe. + if (cDstImage != cSrcImage || cDstLayers != cSrcLayers) { + ctx->copyImage( + cDstImage, cDstLayers, cDstOffset, + cSrcImage, cSrcLayers, cSrcOffset, + cExtent); + } else { + ctx->copyImageRegion( + cDstImage, cDstLayers, cDstOffset, + cSrcOffset, cExtent); + } + }); + } else { + // Since each subresource uses a dedicated buffer, we are going + // to need one call per subresource for staging resource copies + for (uint32_t i = 0; i < pDstLayers->layerCount; i++) { + uint32_t dstSubresource = D3D11CalcSubresource(pDstLayers->mipLevel, pDstLayers->baseArrayLayer + i, pDstTexture->Desc()->MipLevels); + uint32_t srcSubresource = D3D11CalcSubresource(pSrcLayers->mipLevel, pSrcLayers->baseArrayLayer + i, pSrcTexture->Desc()->MipLevels); + + // For multi-plane image data stored in a buffer, the backend + // assumes that the second plane immediately follows the first + // plane in memory, which is only true if we copy the full image. + uint32_t planeCount = 1; + + if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) { + bool needsSeparateCopies = !dstIsImage && !srcIsImage; + + if (!dstIsImage) + needsSeparateCopies |= pDstTexture->MipLevelExtent(pDstLayers->mipLevel) != SrcExtent; + if (!srcIsImage) + needsSeparateCopies |= pSrcTexture->MipLevelExtent(pSrcLayers->mipLevel) != SrcExtent; + + if (needsSeparateCopies) + planeCount = vk::getPlaneCount(srcFormatInfo->aspectMask); + } + + for (uint32_t j = 0; j < planeCount; j++) { + VkImageAspectFlags dstAspectMask = dstFormatInfo->aspectMask; + VkImageAspectFlags srcAspectMask = srcFormatInfo->aspectMask; + + if (planeCount > 1) { + dstAspectMask = vk::getPlaneAspect(j); + srcAspectMask = dstAspectMask; + } + + if (dstIsImage) { + VkImageSubresourceLayers dstLayer = { dstAspectMask, + pDstLayers->mipLevel, pDstLayers->baseArrayLayer + i, 1 }; + + EmitCs([ + cDstImage = pDstTexture->GetImage(), + cDstLayers = dstLayer, + cDstOffset = DstOffset, + cDstExtent = dstExtent, + cSrcBuffer = pSrcTexture->GetMappedBuffer(srcSubresource), + cSrcLayout = pSrcTexture->GetSubresourceLayout(srcAspectMask, srcSubresource), + cSrcOffset = pSrcTexture->ComputeMappedOffset(srcSubresource, j, SrcOffset), + cSrcCoord = SrcOffset, + cSrcExtent = srcMipExtent, + cSrcFormat = pSrcTexture->GetPackedFormat() + ] (DxvkContext* ctx) { + if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + ctx->copyBufferToImage(cDstImage, cDstLayers, cDstOffset, cDstExtent, + cSrcBuffer, cSrcOffset, cSrcLayout.RowPitch, cSrcLayout.DepthPitch); + } else { + ctx->copyPackedBufferToDepthStencilImage(cDstImage, cDstLayers, + VkOffset2D { cDstOffset.x, cDstOffset.y }, + VkExtent2D { cDstExtent.width, cDstExtent.height }, + cSrcBuffer, cSrcLayout.Offset, + VkOffset2D { cSrcCoord.x, cSrcCoord.y }, + VkExtent2D { cSrcExtent.width, cSrcExtent.height }, + cSrcFormat); + } + }); + } else if (srcIsImage) { + VkImageSubresourceLayers srcLayer = { srcAspectMask, + pSrcLayers->mipLevel, pSrcLayers->baseArrayLayer + i, 1 }; + + EmitCs([ + cSrcImage = pSrcTexture->GetImage(), + cSrcLayers = srcLayer, + cSrcOffset = SrcOffset, + cSrcExtent = SrcExtent, + cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource), + cDstLayout = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource), + cDstOffset = pDstTexture->ComputeMappedOffset(dstSubresource, j, DstOffset), + cDstCoord = DstOffset, + cDstExtent = dstMipExtent, + cDstFormat = pDstTexture->GetPackedFormat() + ] (DxvkContext* ctx) { + if (cSrcLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + ctx->copyImageToBuffer(cDstBuffer, cDstOffset, cDstLayout.RowPitch, + cDstLayout.DepthPitch, cSrcImage, cSrcLayers, cSrcOffset, cSrcExtent); + } else { + ctx->copyDepthStencilImageToPackedBuffer(cDstBuffer, cDstLayout.Offset, + VkOffset2D { cDstCoord.x, cDstCoord.y }, + VkExtent2D { cDstExtent.width, cDstExtent.height }, + cSrcImage, cSrcLayers, + VkOffset2D { cSrcOffset.x, cSrcOffset.y }, + VkExtent2D { cSrcExtent.width, cSrcExtent.height }, + cDstFormat); + } + }); + } else { + // The backend is not aware of image metadata in this case, + // so we need to handle image planes and block sizes here + VkDeviceSize elementSize = dstFormatInfo->elementSize; + VkExtent3D dstBlockSize = dstFormatInfo->blockSize; + VkExtent3D srcBlockSize = srcFormatInfo->blockSize; + VkExtent3D planeBlockSize = { 1u, 1u, 1u }; + + if (planeCount > 1) { + auto plane = &dstFormatInfo->planes[j]; + dstBlockSize.width *= plane->blockSize.width; + dstBlockSize.height *= plane->blockSize.height; + srcBlockSize.width *= plane->blockSize.width; + srcBlockSize.height *= plane->blockSize.height; + + planeBlockSize.width = plane->blockSize.width; + planeBlockSize.height = plane->blockSize.height; + elementSize = plane->elementSize; + } + + EmitCs([ + cPixelSize = elementSize, + cSrcBuffer = pSrcTexture->GetMappedBuffer(srcSubresource), + cSrcStart = pSrcTexture->GetSubresourceLayout(srcAspectMask, srcSubresource).Offset, + cSrcOffset = util::computeBlockOffset(SrcOffset, srcBlockSize), + cSrcSize = util::computeBlockCount(srcMipExtent, srcBlockSize), + cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource), + cDstStart = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource).Offset, + cDstOffset = util::computeBlockOffset(DstOffset, dstBlockSize), + cDstSize = util::computeBlockCount(dstMipExtent, dstBlockSize), + cExtent = util::computeBlockCount(blockCount, planeBlockSize) + ] (DxvkContext* ctx) { + ctx->copyPackedBufferImage( + cDstBuffer, cDstStart, cDstOffset, cDstSize, + cSrcBuffer, cSrcStart, cSrcOffset, cSrcSize, + cExtent, cPixelSize); + }); + } + } + } + } + } + + + void D3D11DeviceContext::DiscardBuffer( + ID3D11Resource* pResource) { + auto buffer = static_cast<D3D11Buffer*>(pResource); + + if (buffer->GetMapMode() != D3D11_COMMON_BUFFER_MAP_MODE_NONE) { + D3D11_MAPPED_SUBRESOURCE sr; + + Map(pResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &sr); + Unmap(pResource, 0); + } + } + + + void D3D11DeviceContext::DiscardTexture( + ID3D11Resource* pResource, + UINT Subresource) { + auto texture = GetCommonTexture(pResource); + + if (texture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) { + D3D11_MAPPED_SUBRESOURCE sr; + + Map(pResource, Subresource, D3D11_MAP_WRITE_DISCARD, 0, &sr); + Unmap(pResource, Subresource); + } + } + + + void D3D11DeviceContext::UpdateImage( + D3D11CommonTexture* pDstTexture, + const VkImageSubresource* pDstSubresource, + VkOffset3D DstOffset, + VkExtent3D DstExtent, + DxvkBufferSlice StagingBuffer) { + bool dstIsImage = pDstTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING; + + if (dstIsImage) { + EmitCs([ + cDstImage = pDstTexture->GetImage(), + cDstLayers = vk::makeSubresourceLayers(*pDstSubresource), + cDstOffset = DstOffset, + cDstExtent = DstExtent, + cStagingSlice = std::move(StagingBuffer), + cPackedFormat = pDstTexture->GetPackedFormat() + ] (DxvkContext* ctx) { + if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + ctx->copyBufferToImage(cDstImage, + cDstLayers, cDstOffset, cDstExtent, + cStagingSlice.buffer(), + cStagingSlice.offset(), 0, 0); + } else { + ctx->copyPackedBufferToDepthStencilImage(cDstImage, cDstLayers, + VkOffset2D { cDstOffset.x, cDstOffset.y }, + VkExtent2D { cDstExtent.width, cDstExtent.height }, + cStagingSlice.buffer(), + cStagingSlice.offset(), + VkOffset2D { 0, 0 }, + VkExtent2D { cDstExtent.width, cDstExtent.height }, + cPackedFormat); + } + }); + } else { + // If the destination image is backed only by a buffer, we need to use + // the packed buffer copy function which does not know about planes and + // format metadata, so deal with it manually here. + VkExtent3D dstMipExtent = pDstTexture->MipLevelExtent(pDstSubresource->mipLevel); + + uint32_t dstSubresource = D3D11CalcSubresource(pDstSubresource->mipLevel, + pDstSubresource->arrayLayer, pDstTexture->Desc()->MipLevels); + + auto dstFormat = pDstTexture->GetPackedFormat(); + auto dstFormatInfo = imageFormatInfo(dstFormat); + + uint32_t planeCount = 1; + + if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) + planeCount = vk::getPlaneCount(dstFormatInfo->aspectMask); + + // The source data isn't stored in an image so we'll also need to + // track the offset for that while iterating over the planes. + VkDeviceSize srcPlaneOffset = 0; + + for (uint32_t i = 0; i < planeCount; i++) { + VkImageAspectFlags dstAspectMask = dstFormatInfo->aspectMask; + VkDeviceSize elementSize = dstFormatInfo->elementSize; + VkExtent3D blockSize = dstFormatInfo->blockSize; + + if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) { + dstAspectMask = vk::getPlaneAspect(i); + + auto plane = &dstFormatInfo->planes[i]; + blockSize.width *= plane->blockSize.width; + blockSize.height *= plane->blockSize.height; + elementSize = plane->elementSize; + } + + VkExtent3D blockCount = util::computeBlockCount(DstExtent, blockSize); + + EmitCs([ + cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource), + cDstStart = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource).Offset, + cDstOffset = util::computeBlockOffset(DstOffset, blockSize), + cDstSize = util::computeBlockCount(dstMipExtent, blockSize), + cDstExtent = blockCount, + cSrcBuffer = StagingBuffer.buffer(), + cSrcStart = StagingBuffer.offset() + srcPlaneOffset, + cPixelSize = elementSize + ] (DxvkContext* ctx) { + ctx->copyPackedBufferImage( + cDstBuffer, cDstStart, cDstOffset, cDstSize, + cSrcBuffer, cSrcStart, VkOffset3D(), cDstExtent, + cDstExtent, cPixelSize); + }); + + srcPlaneOffset += util::flattenImageExtent(blockCount) * elementSize; + } + } + } + + + void D3D11DeviceContext::SetDrawBuffers( + ID3D11Buffer* pBufferForArgs, + ID3D11Buffer* pBufferForCount) { + auto argBuffer = static_cast<D3D11Buffer*>(pBufferForArgs); + auto cntBuffer = static_cast<D3D11Buffer*>(pBufferForCount); + + if (m_state.id.argBuffer != argBuffer + || m_state.id.cntBuffer != cntBuffer) { + m_state.id.argBuffer = argBuffer; + m_state.id.cntBuffer = cntBuffer; + + BindDrawBuffers(argBuffer, cntBuffer); + } + } + + + template<DxbcProgramType ShaderStage> + void D3D11DeviceContext::SetConstantBuffers( + D3D11ConstantBufferBindings& Bindings, + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers) { + uint32_t slotId = computeConstantBufferBinding(ShaderStage, StartSlot); + + for (uint32_t i = 0; i < NumBuffers; i++) { + auto newBuffer = static_cast<D3D11Buffer*>(ppConstantBuffers[i]); + + UINT constantCount = 0; + + if (likely(newBuffer != nullptr)) + constantCount = std::min(newBuffer->Desc()->ByteWidth / 16, UINT(D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT)); + + if (Bindings[StartSlot + i].buffer != newBuffer + || Bindings[StartSlot + i].constantCount != constantCount) { + Bindings[StartSlot + i].buffer = newBuffer; + Bindings[StartSlot + i].constantOffset = 0; + Bindings[StartSlot + i].constantCount = constantCount; + Bindings[StartSlot + i].constantBound = constantCount; + + BindConstantBuffer(slotId + i, newBuffer, 0, constantCount); + } + } + } + + + template<DxbcProgramType ShaderStage> + void D3D11DeviceContext::SetConstantBuffers1( + D3D11ConstantBufferBindings& Bindings, + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants) { + uint32_t slotId = computeConstantBufferBinding(ShaderStage, StartSlot); + + for (uint32_t i = 0; i < NumBuffers; i++) { + auto newBuffer = static_cast<D3D11Buffer*>(ppConstantBuffers[i]); + + UINT constantOffset; + UINT constantCount; + UINT constantBound; + + if (likely(newBuffer != nullptr)) { + UINT bufferConstantsCount = newBuffer->Desc()->ByteWidth / 16; + constantBound = std::min(bufferConstantsCount, UINT(D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT)); + + if (likely(pFirstConstant && pNumConstants)) { + constantOffset = pFirstConstant[i]; + constantCount = pNumConstants [i]; + + if (unlikely(constantCount > D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT)) + continue; + + constantBound = (constantOffset + constantCount > bufferConstantsCount) + ? bufferConstantsCount - std::min(constantOffset, bufferConstantsCount) + : constantCount; + } else { + constantOffset = 0; + constantCount = constantBound; + } + } else { + constantOffset = 0; + constantCount = 0; + constantBound = 0; + } + + bool needsUpdate = Bindings[StartSlot + i].buffer != newBuffer; + + if (needsUpdate) + Bindings[StartSlot + i].buffer = newBuffer; + + needsUpdate |= Bindings[StartSlot + i].constantOffset != constantOffset + || Bindings[StartSlot + i].constantCount != constantCount; + + if (needsUpdate) { + Bindings[StartSlot + i].constantOffset = constantOffset; + Bindings[StartSlot + i].constantCount = constantCount; + Bindings[StartSlot + i].constantBound = constantBound; + + BindConstantBuffer(slotId + i, newBuffer, constantOffset, constantBound); + } + } + } + + + template<DxbcProgramType ShaderStage> + void D3D11DeviceContext::SetSamplers( + D3D11SamplerBindings& Bindings, + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers) { + uint32_t slotId = computeSamplerBinding(ShaderStage, StartSlot); + + for (uint32_t i = 0; i < NumSamplers; i++) { + auto sampler = static_cast<D3D11SamplerState*>(ppSamplers[i]); + + if (Bindings[StartSlot + i] != sampler) { + Bindings[StartSlot + i] = sampler; + BindSampler(slotId + i, sampler); + } + } + } + + + template<DxbcProgramType ShaderStage> + void D3D11DeviceContext::SetShaderResources( + D3D11ShaderResourceBindings& Bindings, + UINT StartSlot, + UINT NumResources, + ID3D11ShaderResourceView* const* ppResources) { + uint32_t slotId = computeSrvBinding(ShaderStage, StartSlot); + + for (uint32_t i = 0; i < NumResources; i++) { + auto resView = static_cast<D3D11ShaderResourceView*>(ppResources[i]); + + if (Bindings.views[StartSlot + i] != resView) { + if (unlikely(resView && resView->TestHazards())) { + if (TestSrvHazards<ShaderStage>(resView)) + resView = nullptr; + + // Only set if necessary, but don't reset it on every + // bind as this would be more expensive than a few + // redundant checks in OMSetRenderTargets and friends. + Bindings.hazardous.set(StartSlot + i, resView); + } + + Bindings.views[StartSlot + i] = resView; + BindShaderResource(slotId + i, resView); + } + } + } + + + void D3D11DeviceContext::GetConstantBuffers( + const D3D11ConstantBufferBindings& Bindings, + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants) { + for (uint32_t i = 0; i < NumBuffers; i++) { + const bool inRange = StartSlot + i < Bindings.size(); + + if (ppConstantBuffers != nullptr) { + ppConstantBuffers[i] = inRange + ? Bindings[StartSlot + i].buffer.ref() + : nullptr; + } + + if (pFirstConstant != nullptr) { + pFirstConstant[i] = inRange + ? Bindings[StartSlot + i].constantOffset + : 0u; + } + + if (pNumConstants != nullptr) { + pNumConstants[i] = inRange + ? Bindings[StartSlot + i].constantCount + : 0u; + } + } + } + + + void D3D11DeviceContext::GetShaderResources( + const D3D11ShaderResourceBindings& Bindings, + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews) { + for (uint32_t i = 0; i < NumViews; i++) { + ppShaderResourceViews[i] = StartSlot + i < Bindings.views.size() + ? Bindings.views[StartSlot + i].ref() + : nullptr; + } + } + + + void D3D11DeviceContext::GetSamplers( + const D3D11SamplerBindings& Bindings, + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers) { + for (uint32_t i = 0; i < NumSamplers; i++) { + ppSamplers[i] = StartSlot + i < Bindings.size() + ? ref(Bindings[StartSlot + i]) + : nullptr; + } + } + + + void D3D11DeviceContext::ResetState() { + EmitCs([] (DxvkContext* ctx) { + // Reset render targets + ctx->bindRenderTargets(DxvkRenderTargets()); + + // Reset vertex input state + ctx->setInputLayout(0, nullptr, 0, nullptr); + + // Reset render states + DxvkInputAssemblyState iaState; + InitDefaultPrimitiveTopology(&iaState); + + DxvkDepthStencilState dsState; + InitDefaultDepthStencilState(&dsState); + + DxvkRasterizerState rsState; + InitDefaultRasterizerState(&rsState); + + DxvkBlendMode cbState; + DxvkLogicOpState loState; + DxvkMultisampleState msState; + InitDefaultBlendState(&cbState, &loState, &msState, D3D11_DEFAULT_SAMPLE_MASK); + + ctx->setInputAssemblyState(iaState); + ctx->setDepthStencilState(dsState); + ctx->setRasterizerState(rsState); + ctx->setLogicOpState(loState); + ctx->setMultisampleState(msState); + + for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + ctx->setBlendMode(i, cbState); + + // Reset dynamic states + ctx->setBlendConstants(DxvkBlendConstants { 1.0f, 1.0f, 1.0f, 1.0f }); + ctx->setStencilReference(D3D11_DEFAULT_STENCIL_REFERENCE); + + // Reset viewports + auto viewport = VkViewport(); + auto scissor = VkRect2D(); + + ctx->setViewports(1, &viewport, &scissor); + + // Unbind indirect draw buffer + ctx->bindDrawBuffers(DxvkBufferSlice(), DxvkBufferSlice()); + + // Unbind index and vertex buffers + ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32); + + for (uint32_t i = 0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) + ctx->bindVertexBuffer(i, DxvkBufferSlice(), 0); + + // Unbind transform feedback buffers + for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) + ctx->bindXfbBuffer(i, DxvkBufferSlice(), DxvkBufferSlice()); + + // Unbind per-shader stage resources + for (uint32_t i = 0; i < 6; i++) { + auto programType = DxbcProgramType(i); + ctx->bindShader(GetShaderStage(programType), nullptr); + + // Unbind constant buffers, including the shader's ICB + auto cbSlotId = computeConstantBufferBinding(programType, 0); + + for (uint32_t j = 0; j <= D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; j++) + ctx->bindResourceBuffer(cbSlotId + j, DxvkBufferSlice()); + + // Unbind shader resource views + auto srvSlotId = computeSrvBinding(programType, 0); + + for (uint32_t j = 0; j < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; j++) + ctx->bindResourceView(srvSlotId + j, nullptr, nullptr); + + // Unbind texture samplers + auto samplerSlotId = computeSamplerBinding(programType, 0); + + for (uint32_t j = 0; j < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; j++) + ctx->bindResourceSampler(samplerSlotId + j, nullptr); + + // Unbind UAVs for supported stages + if (programType == DxbcProgramType::PixelShader + || programType == DxbcProgramType::ComputeShader) { + auto uavSlotId = computeUavBinding(programType, 0); + auto ctrSlotId = computeUavCounterBinding(programType, 0); + + for (uint32_t j = 0; j < D3D11_1_UAV_SLOT_COUNT; j++) { + ctx->bindResourceView (uavSlotId, nullptr, nullptr); + ctx->bindResourceBuffer (ctrSlotId, DxvkBufferSlice()); + } + } + } + }); + } + + + void D3D11DeviceContext::RestoreState() { + BindFramebuffer(); + + BindShader<DxbcProgramType::VertexShader> (GetCommonShader(m_state.vs.shader.ptr())); + BindShader<DxbcProgramType::HullShader> (GetCommonShader(m_state.hs.shader.ptr())); + BindShader<DxbcProgramType::DomainShader> (GetCommonShader(m_state.ds.shader.ptr())); + BindShader<DxbcProgramType::GeometryShader> (GetCommonShader(m_state.gs.shader.ptr())); + BindShader<DxbcProgramType::PixelShader> (GetCommonShader(m_state.ps.shader.ptr())); + BindShader<DxbcProgramType::ComputeShader> (GetCommonShader(m_state.cs.shader.ptr())); + + ApplyInputLayout(); + ApplyPrimitiveTopology(); + ApplyBlendState(); + ApplyBlendFactor(); + ApplyDepthStencilState(); + ApplyStencilRef(); + ApplyRasterizerState(); + ApplyViewportState(); + + BindDrawBuffers( + m_state.id.argBuffer.ptr(), + m_state.id.cntBuffer.ptr()); + + BindIndexBuffer( + m_state.ia.indexBuffer.buffer.ptr(), + m_state.ia.indexBuffer.offset, + m_state.ia.indexBuffer.format); + + for (uint32_t i = 0; i < m_state.ia.vertexBuffers.size(); i++) { + BindVertexBuffer(i, + m_state.ia.vertexBuffers[i].buffer.ptr(), + m_state.ia.vertexBuffers[i].offset, + m_state.ia.vertexBuffers[i].stride); + } + + for (uint32_t i = 0; i < m_state.so.targets.size(); i++) + BindXfbBuffer(i, m_state.so.targets[i].buffer.ptr(), ~0u); + + RestoreConstantBuffers<DxbcProgramType::VertexShader> (m_state.vs.constantBuffers); + RestoreConstantBuffers<DxbcProgramType::HullShader> (m_state.hs.constantBuffers); + RestoreConstantBuffers<DxbcProgramType::DomainShader> (m_state.ds.constantBuffers); + RestoreConstantBuffers<DxbcProgramType::GeometryShader> (m_state.gs.constantBuffers); + RestoreConstantBuffers<DxbcProgramType::PixelShader> (m_state.ps.constantBuffers); + RestoreConstantBuffers<DxbcProgramType::ComputeShader> (m_state.cs.constantBuffers); + + RestoreSamplers<DxbcProgramType::VertexShader> (m_state.vs.samplers); + RestoreSamplers<DxbcProgramType::HullShader> (m_state.hs.samplers); + RestoreSamplers<DxbcProgramType::DomainShader> (m_state.ds.samplers); + RestoreSamplers<DxbcProgramType::GeometryShader>(m_state.gs.samplers); + RestoreSamplers<DxbcProgramType::PixelShader> (m_state.ps.samplers); + RestoreSamplers<DxbcProgramType::ComputeShader> (m_state.cs.samplers); + + RestoreShaderResources<DxbcProgramType::VertexShader> (m_state.vs.shaderResources); + RestoreShaderResources<DxbcProgramType::HullShader> (m_state.hs.shaderResources); + RestoreShaderResources<DxbcProgramType::DomainShader> (m_state.ds.shaderResources); + RestoreShaderResources<DxbcProgramType::GeometryShader> (m_state.gs.shaderResources); + RestoreShaderResources<DxbcProgramType::PixelShader> (m_state.ps.shaderResources); + RestoreShaderResources<DxbcProgramType::ComputeShader> (m_state.cs.shaderResources); + + RestoreUnorderedAccessViews<DxbcProgramType::PixelShader> (m_state.ps.unorderedAccessViews); + RestoreUnorderedAccessViews<DxbcProgramType::ComputeShader> (m_state.cs.unorderedAccessViews); + } + + + template<DxbcProgramType Stage> + void D3D11DeviceContext::RestoreConstantBuffers( + D3D11ConstantBufferBindings& Bindings) { + uint32_t slotId = computeConstantBufferBinding(Stage, 0); + + for (uint32_t i = 0; i < Bindings.size(); i++) { + BindConstantBuffer(slotId + i, Bindings[i].buffer.ptr(), + Bindings[i].constantOffset, Bindings[i].constantBound); + } + } + + + template<DxbcProgramType Stage> + void D3D11DeviceContext::RestoreSamplers( + D3D11SamplerBindings& Bindings) { + uint32_t slotId = computeSamplerBinding(Stage, 0); + + for (uint32_t i = 0; i < Bindings.size(); i++) + BindSampler(slotId + i, Bindings[i]); + } + + + template<DxbcProgramType Stage> + void D3D11DeviceContext::RestoreShaderResources( + D3D11ShaderResourceBindings& Bindings) { + uint32_t slotId = computeSrvBinding(Stage, 0); + + for (uint32_t i = 0; i < Bindings.views.size(); i++) + BindShaderResource(slotId + i, Bindings.views[i].ptr()); + } + + + template<DxbcProgramType Stage> + void D3D11DeviceContext::RestoreUnorderedAccessViews( + D3D11UnorderedAccessBindings& Bindings) { + uint32_t uavSlotId = computeUavBinding (Stage, 0); + uint32_t ctrSlotId = computeUavCounterBinding(Stage, 0); + + for (uint32_t i = 0; i < Bindings.size(); i++) { + BindUnorderedAccessView( + uavSlotId + i, + Bindings[i].ptr(), + ctrSlotId + i, ~0u); + } + } + + + bool D3D11DeviceContext::TestRtvUavHazards( + UINT NumRTVs, + ID3D11RenderTargetView* const* ppRTVs, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUAVs) { + if (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) NumRTVs = 0; + if (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS) NumUAVs = 0; + + for (uint32_t i = 0; i < NumRTVs; i++) { + auto rtv = static_cast<D3D11RenderTargetView*>(ppRTVs[i]); + + if (!rtv) + continue; + + for (uint32_t j = 0; j < i; j++) { + if (CheckViewOverlap(rtv, static_cast<D3D11RenderTargetView*>(ppRTVs[j]))) + return true; + } + + if (rtv->HasBindFlag(D3D11_BIND_UNORDERED_ACCESS)) { + for (uint32_t j = 0; j < NumUAVs; j++) { + if (CheckViewOverlap(rtv, static_cast<D3D11UnorderedAccessView*>(ppUAVs[j]))) + return true; + } + } + } + + for (uint32_t i = 0; i < NumUAVs; i++) { + auto uav = static_cast<D3D11UnorderedAccessView*>(ppUAVs[i]); + + if (!uav) + continue; + + for (uint32_t j = 0; j < i; j++) { + if (CheckViewOverlap(uav, static_cast<D3D11UnorderedAccessView*>(ppUAVs[j]))) + return true; + } + } + + return false; + } + + + template<DxbcProgramType ShaderStage> + bool D3D11DeviceContext::TestSrvHazards( + D3D11ShaderResourceView* pView) { + bool hazard = false; + + if (ShaderStage == DxbcProgramType::ComputeShader) { + int32_t uav = m_state.cs.uavMask.findNext(0); + + while (uav >= 0 && !hazard) { + hazard = CheckViewOverlap(pView, m_state.cs.unorderedAccessViews[uav].ptr()); + uav = m_state.cs.uavMask.findNext(uav + 1); + } + } else { + hazard = CheckViewOverlap(pView, m_state.om.depthStencilView.ptr()); + + for (uint32_t i = 0; !hazard && i < m_state.om.maxRtv; i++) + hazard = CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr()); + + for (uint32_t i = 0; !hazard && i < m_state.om.maxUav; i++) + hazard = CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr()); + } + + return hazard; + } + + + template<DxbcProgramType ShaderStage, typename T> + void D3D11DeviceContext::ResolveSrvHazards( + T* pView, + D3D11ShaderResourceBindings& Bindings) { + uint32_t slotId = computeSrvBinding(ShaderStage, 0); + int32_t srvId = Bindings.hazardous.findNext(0); + + while (srvId >= 0) { + auto srv = Bindings.views[srvId].ptr(); + + if (likely(srv && srv->TestHazards())) { + bool hazard = CheckViewOverlap(pView, srv); + + if (unlikely(hazard)) { + Bindings.views[srvId] = nullptr; + Bindings.hazardous.clr(srvId); + + BindShaderResource(slotId + srvId, nullptr); + } + } else { + // Avoid further redundant iterations + Bindings.hazardous.clr(srvId); + } + + srvId = Bindings.hazardous.findNext(srvId + 1); + } + } + + + template<typename T> + void D3D11DeviceContext::ResolveCsSrvHazards( + T* pView) { + if (!pView) return; + ResolveSrvHazards<DxbcProgramType::ComputeShader> (pView, m_state.cs.shaderResources); + } + + + template<typename T> + void D3D11DeviceContext::ResolveOmSrvHazards( + T* pView) { + if (!pView) return; + ResolveSrvHazards<DxbcProgramType::VertexShader> (pView, m_state.vs.shaderResources); + ResolveSrvHazards<DxbcProgramType::HullShader> (pView, m_state.hs.shaderResources); + ResolveSrvHazards<DxbcProgramType::DomainShader> (pView, m_state.ds.shaderResources); + ResolveSrvHazards<DxbcProgramType::GeometryShader> (pView, m_state.gs.shaderResources); + ResolveSrvHazards<DxbcProgramType::PixelShader> (pView, m_state.ps.shaderResources); + } + + + bool D3D11DeviceContext::ResolveOmRtvHazards( + D3D11UnorderedAccessView* pView) { + if (!pView || !pView->HasBindFlag(D3D11_BIND_RENDER_TARGET)) + return false; + + bool hazard = false; + + if (CheckViewOverlap(pView, m_state.om.depthStencilView.ptr())) { + m_state.om.depthStencilView = nullptr; + hazard = true; + } + + for (uint32_t i = 0; i < m_state.om.maxRtv; i++) { + if (CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr())) { + m_state.om.renderTargetViews[i] = nullptr; + hazard = true; + } + } + + return hazard; + } + + + void D3D11DeviceContext::ResolveOmUavHazards( + D3D11RenderTargetView* pView) { + if (!pView || !pView->HasBindFlag(D3D11_BIND_UNORDERED_ACCESS)) + return; + + uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0); + uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0); + + for (uint32_t i = 0; i < m_state.om.maxUav; i++) { + if (CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr())) { + m_state.ps.unorderedAccessViews[i] = nullptr; + + BindUnorderedAccessView( + uavSlotId + i, nullptr, + ctrSlotId + i, ~0u); + } + } + } + + + bool D3D11DeviceContext::ValidateRenderTargets( + UINT NumViews, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView) { + Rc<DxvkImageView> refView; + + if (pDepthStencilView != nullptr) { + refView = static_cast<D3D11DepthStencilView*>( + pDepthStencilView)->GetImageView(); + } + + for (uint32_t i = 0; i < NumViews; i++) { + if (ppRenderTargetViews[i] != nullptr) { + auto curView = static_cast<D3D11RenderTargetView*>( + ppRenderTargetViews[i])->GetImageView(); + + if (refView != nullptr) { + // Render target views must all have the same + // size, sample count, layer count, and type + if (curView->info().type != refView->info().type + || curView->info().numLayers != refView->info().numLayers) + return false; + + if (curView->imageInfo().sampleCount + != refView->imageInfo().sampleCount) + return false; + } else { + // Set reference view. All remaining views + // must be compatible to the reference view. + refView = curView; + } + } + } + + return true; + } + + + VkClearValue D3D11DeviceContext::ConvertColorValue( + const FLOAT Color[4], + const DxvkFormatInfo* pFormatInfo) { + VkClearValue result; + + if (pFormatInfo->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { + for (uint32_t i = 0; i < 4; i++) { + if (pFormatInfo->flags.test(DxvkFormatFlag::SampledUInt)) + result.color.uint32[i] = uint32_t(std::max(0.0f, Color[i])); + else if (pFormatInfo->flags.test(DxvkFormatFlag::SampledSInt)) + result.color.int32[i] = int32_t(Color[i]); + else + result.color.float32[i] = Color[i]; + } + } else { + result.depthStencil.depth = Color[0]; + result.depthStencil.stencil = 0; + } + + return result; + } + + + DxvkDataSlice D3D11DeviceContext::AllocUpdateBufferSlice(size_t Size) { + constexpr size_t UpdateBufferSize = 16 * 1024 * 1024; + + if (Size >= UpdateBufferSize) { + Rc<DxvkDataBuffer> buffer = new DxvkDataBuffer(Size); + return buffer->alloc(Size); + } else { + if (m_updateBuffer == nullptr) + m_updateBuffer = new DxvkDataBuffer(UpdateBufferSize); + + DxvkDataSlice slice = m_updateBuffer->alloc(Size); + + if (slice.ptr() == nullptr) { + m_updateBuffer = new DxvkDataBuffer(UpdateBufferSize); + slice = m_updateBuffer->alloc(Size); + } + + return slice; + } + } + + + DxvkBufferSlice D3D11DeviceContext::AllocStagingBuffer( + VkDeviceSize Size) { + DxvkBufferCreateInfo info; + info.size = Size; + info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT + | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT + | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT + | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + info.access = VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_SHADER_READ_BIT; + + return DxvkBufferSlice(m_device->createBuffer(info, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)); + } + + + DxvkCsChunkRef D3D11DeviceContext::AllocCsChunk() { + return m_parent->AllocCsChunk(m_csFlags); + } + + + void D3D11DeviceContext::InitDefaultPrimitiveTopology( + DxvkInputAssemblyState* pIaState) { + pIaState->primitiveTopology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + pIaState->primitiveRestart = VK_FALSE; + pIaState->patchVertexCount = 0; + } + + + void D3D11DeviceContext::InitDefaultRasterizerState( + DxvkRasterizerState* pRsState) { + pRsState->polygonMode = VK_POLYGON_MODE_FILL; + pRsState->cullMode = VK_CULL_MODE_BACK_BIT; + pRsState->frontFace = VK_FRONT_FACE_CLOCKWISE; + pRsState->depthClipEnable = VK_TRUE; + pRsState->depthBiasEnable = VK_FALSE; + pRsState->conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT; + pRsState->sampleCount = 0; + } + + + void D3D11DeviceContext::InitDefaultDepthStencilState( + DxvkDepthStencilState* pDsState) { + VkStencilOpState stencilOp; + stencilOp.failOp = VK_STENCIL_OP_KEEP; + stencilOp.passOp = VK_STENCIL_OP_KEEP; + stencilOp.depthFailOp = VK_STENCIL_OP_KEEP; + stencilOp.compareOp = VK_COMPARE_OP_ALWAYS; + stencilOp.compareMask = D3D11_DEFAULT_STENCIL_READ_MASK; + stencilOp.writeMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + stencilOp.reference = 0; + + pDsState->enableDepthTest = VK_TRUE; + pDsState->enableDepthWrite = VK_TRUE; + pDsState->enableStencilTest = VK_FALSE; + pDsState->depthCompareOp = VK_COMPARE_OP_LESS; + pDsState->stencilOpFront = stencilOp; + pDsState->stencilOpBack = stencilOp; + } + + + void D3D11DeviceContext::InitDefaultBlendState( + DxvkBlendMode* pCbState, + DxvkLogicOpState* pLoState, + DxvkMultisampleState* pMsState, + UINT SampleMask) { + pCbState->enableBlending = VK_FALSE; + pCbState->colorSrcFactor = VK_BLEND_FACTOR_ONE; + pCbState->colorDstFactor = VK_BLEND_FACTOR_ZERO; + pCbState->colorBlendOp = VK_BLEND_OP_ADD; + pCbState->alphaSrcFactor = VK_BLEND_FACTOR_ONE; + pCbState->alphaDstFactor = VK_BLEND_FACTOR_ZERO; + pCbState->alphaBlendOp = VK_BLEND_OP_ADD; + pCbState->writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT + | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + pLoState->enableLogicOp = VK_FALSE; + pLoState->logicOp = VK_LOGIC_OP_NO_OP; + + pMsState->sampleMask = SampleMask; + pMsState->enableAlphaToCoverage = VK_FALSE; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.h new file mode 100644 index 00000000..483b0415 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.h @@ -0,0 +1,1011 @@ +#pragma once + +#include "../dxvk/dxvk_adapter.h" +#include "../dxvk/dxvk_cs.h" +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_multithread.h" + +#include "d3d11_annotation.h" +#include "d3d11_cmd.h" +#include "d3d11_context_ext.h" +#include "d3d11_context_state.h" +#include "d3d11_device_child.h" +#include "d3d11_texture.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11DeviceContext : public D3D11DeviceChild<ID3D11DeviceContext4> { + friend class D3D11DeviceContextExt; + // Needed in order to call EmitCs for pushing markers + friend class D3D11UserDefinedAnnotation; + public: + + D3D11DeviceContext( + D3D11Device* pParent, + const Rc<DxvkDevice>& Device, + DxvkCsChunkFlags CsFlags); + ~D3D11DeviceContext(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void STDMETHODCALLTYPE DiscardResource(ID3D11Resource *pResource); + + void STDMETHODCALLTYPE DiscardView(ID3D11View* pResourceView); + + void STDMETHODCALLTYPE DiscardView1( + ID3D11View* pResourceView, + const D3D11_RECT* pRects, + UINT NumRects); + + void STDMETHODCALLTYPE ClearState(); + + void STDMETHODCALLTYPE SetPredication( + ID3D11Predicate* pPredicate, + BOOL PredicateValue); + + void STDMETHODCALLTYPE GetPredication( + ID3D11Predicate** ppPredicate, + BOOL* pPredicateValue); + + void STDMETHODCALLTYPE CopySubresourceRegion( + ID3D11Resource* pDstResource, + UINT DstSubresource, + UINT DstX, + UINT DstY, + UINT DstZ, + ID3D11Resource* pSrcResource, + UINT SrcSubresource, + const D3D11_BOX* pSrcBox); + + void STDMETHODCALLTYPE CopySubresourceRegion1( + ID3D11Resource* pDstResource, + UINT DstSubresource, + UINT DstX, + UINT DstY, + UINT DstZ, + ID3D11Resource* pSrcResource, + UINT SrcSubresource, + const D3D11_BOX* pSrcBox, + UINT CopyFlags); + + void STDMETHODCALLTYPE CopyResource( + ID3D11Resource* pDstResource, + ID3D11Resource* pSrcResource); + + void STDMETHODCALLTYPE CopyStructureCount( + ID3D11Buffer* pDstBuffer, + UINT DstAlignedByteOffset, + ID3D11UnorderedAccessView* pSrcView); + + void STDMETHODCALLTYPE CopyTiles( + ID3D11Resource* pTiledResource, + const D3D11_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate, + const D3D11_TILE_REGION_SIZE* pTileRegionSize, + ID3D11Buffer* pBuffer, + UINT64 BufferStartOffsetInBytes, + UINT Flags); + + HRESULT STDMETHODCALLTYPE CopyTileMappings( + ID3D11Resource* pDestTiledResource, + const D3D11_TILED_RESOURCE_COORDINATE* pDestRegionStartCoordinate, + ID3D11Resource* pSourceTiledResource, + const D3D11_TILED_RESOURCE_COORDINATE* pSourceRegionStartCoordinate, + const D3D11_TILE_REGION_SIZE* pTileRegionSize, + UINT Flags); + + HRESULT STDMETHODCALLTYPE ResizeTilePool( + ID3D11Buffer* pTilePool, + UINT64 NewSizeInBytes); + + void STDMETHODCALLTYPE TiledResourceBarrier( + ID3D11DeviceChild* pTiledResourceOrViewAccessBeforeBarrier, + ID3D11DeviceChild* pTiledResourceOrViewAccessAfterBarrier); + + void STDMETHODCALLTYPE ClearRenderTargetView( + ID3D11RenderTargetView* pRenderTargetView, + const FLOAT ColorRGBA[4]); + + void STDMETHODCALLTYPE ClearUnorderedAccessViewUint( + ID3D11UnorderedAccessView* pUnorderedAccessView, + const UINT Values[4]); + + void STDMETHODCALLTYPE ClearUnorderedAccessViewFloat( + ID3D11UnorderedAccessView* pUnorderedAccessView, + const FLOAT Values[4]); + + void STDMETHODCALLTYPE ClearDepthStencilView( + ID3D11DepthStencilView* pDepthStencilView, + UINT ClearFlags, + FLOAT Depth, + UINT8 Stencil); + + void STDMETHODCALLTYPE ClearView( + ID3D11View *pView, + const FLOAT Color[4], + const D3D11_RECT *pRect, + UINT NumRects); + + void STDMETHODCALLTYPE GenerateMips( + ID3D11ShaderResourceView* pShaderResourceView); + + void STDMETHODCALLTYPE UpdateSubresource( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch); + + void STDMETHODCALLTYPE UpdateSubresource1( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch, + UINT CopyFlags); + + HRESULT STDMETHODCALLTYPE UpdateTileMappings( + ID3D11Resource* pTiledResource, + UINT NumTiledResourceRegions, + const D3D11_TILED_RESOURCE_COORDINATE* pTiledResourceRegionStartCoordinates, + const D3D11_TILE_REGION_SIZE* pTiledResourceRegionSizes, + ID3D11Buffer* pTilePool, + UINT NumRanges, + const UINT* pRangeFlags, + const UINT* pTilePoolStartOffsets, + const UINT* pRangeTileCounts, + UINT Flags); + + void STDMETHODCALLTYPE UpdateTiles( + ID3D11Resource* pDestTiledResource, + const D3D11_TILED_RESOURCE_COORDINATE* pDestTileRegionStartCoordinate, + const D3D11_TILE_REGION_SIZE* pDestTileRegionSize, + const void* pSourceTileData, + UINT Flags); + + void STDMETHODCALLTYPE SetResourceMinLOD( + ID3D11Resource* pResource, + FLOAT MinLOD); + + FLOAT STDMETHODCALLTYPE GetResourceMinLOD( + ID3D11Resource* pResource); + + void STDMETHODCALLTYPE ResolveSubresource( + ID3D11Resource* pDstResource, + UINT DstSubresource, + ID3D11Resource* pSrcResource, + UINT SrcSubresource, + DXGI_FORMAT Format); + + void STDMETHODCALLTYPE DrawAuto(); + + void STDMETHODCALLTYPE Draw( + UINT VertexCount, + UINT StartVertexLocation); + + void STDMETHODCALLTYPE DrawIndexed( + UINT IndexCount, + UINT StartIndexLocation, + INT BaseVertexLocation); + + void STDMETHODCALLTYPE DrawInstanced( + UINT VertexCountPerInstance, + UINT InstanceCount, + UINT StartVertexLocation, + UINT StartInstanceLocation); + + void STDMETHODCALLTYPE DrawIndexedInstanced( + UINT IndexCountPerInstance, + UINT InstanceCount, + UINT StartIndexLocation, + INT BaseVertexLocation, + UINT StartInstanceLocation); + + void STDMETHODCALLTYPE DrawIndexedInstancedIndirect( + ID3D11Buffer* pBufferForArgs, + UINT AlignedByteOffsetForArgs); + + void STDMETHODCALLTYPE DrawInstancedIndirect( + ID3D11Buffer* pBufferForArgs, + UINT AlignedByteOffsetForArgs); + + void STDMETHODCALLTYPE Dispatch( + UINT ThreadGroupCountX, + UINT ThreadGroupCountY, + UINT ThreadGroupCountZ); + + void STDMETHODCALLTYPE DispatchIndirect( + ID3D11Buffer* pBufferForArgs, + UINT AlignedByteOffsetForArgs); + + void STDMETHODCALLTYPE IASetInputLayout( + ID3D11InputLayout* pInputLayout); + + void STDMETHODCALLTYPE IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY Topology); + + void STDMETHODCALLTYPE IASetVertexBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppVertexBuffers, + const UINT* pStrides, + const UINT* pOffsets); + + void STDMETHODCALLTYPE IASetIndexBuffer( + ID3D11Buffer* pIndexBuffer, + DXGI_FORMAT Format, + UINT Offset); + + void STDMETHODCALLTYPE IAGetInputLayout( + ID3D11InputLayout** ppInputLayout); + + void STDMETHODCALLTYPE IAGetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY* pTopology); + + void STDMETHODCALLTYPE IAGetVertexBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppVertexBuffers, + UINT* pStrides, + UINT* pOffsets); + + void STDMETHODCALLTYPE IAGetIndexBuffer( + ID3D11Buffer** ppIndexBuffer, + DXGI_FORMAT* pFormat, + UINT* pOffset); + + void STDMETHODCALLTYPE VSSetShader( + ID3D11VertexShader* pVertexShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances); + + void STDMETHODCALLTYPE VSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers); + + void STDMETHODCALLTYPE VSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants); + + void STDMETHODCALLTYPE VSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews); + + void STDMETHODCALLTYPE VSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers); + + void STDMETHODCALLTYPE VSGetShader( + ID3D11VertexShader** ppVertexShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances); + + void STDMETHODCALLTYPE VSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers); + + void STDMETHODCALLTYPE VSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants); + + void STDMETHODCALLTYPE VSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews); + + void STDMETHODCALLTYPE VSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers); + + void STDMETHODCALLTYPE HSSetShader( + ID3D11HullShader* pHullShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances); + + void STDMETHODCALLTYPE HSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews); + + void STDMETHODCALLTYPE HSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers); + + void STDMETHODCALLTYPE HSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants); + + void STDMETHODCALLTYPE HSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers); + + void STDMETHODCALLTYPE HSGetShader( + ID3D11HullShader** ppHullShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances); + + void STDMETHODCALLTYPE HSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers); + + void STDMETHODCALLTYPE HSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants); + + void STDMETHODCALLTYPE HSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews); + + void STDMETHODCALLTYPE HSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers); + + void STDMETHODCALLTYPE DSSetShader( + ID3D11DomainShader* pDomainShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances); + + void STDMETHODCALLTYPE DSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews); + + void STDMETHODCALLTYPE DSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers); + + void STDMETHODCALLTYPE DSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants); + + void STDMETHODCALLTYPE DSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers); + + void STDMETHODCALLTYPE DSGetShader( + ID3D11DomainShader** ppDomainShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances); + + void STDMETHODCALLTYPE DSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers); + + void STDMETHODCALLTYPE DSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants); + + void STDMETHODCALLTYPE DSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews); + + void STDMETHODCALLTYPE DSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers); + + void STDMETHODCALLTYPE GSSetShader( + ID3D11GeometryShader* pShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances); + + void STDMETHODCALLTYPE GSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers); + + void STDMETHODCALLTYPE GSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants); + + void STDMETHODCALLTYPE GSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews); + + void STDMETHODCALLTYPE GSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers); + + void STDMETHODCALLTYPE GSGetShader( + ID3D11GeometryShader** ppGeometryShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances); + + void STDMETHODCALLTYPE GSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers); + + void STDMETHODCALLTYPE GSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants); + + void STDMETHODCALLTYPE GSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews); + + void STDMETHODCALLTYPE GSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers); + + void STDMETHODCALLTYPE PSSetShader( + ID3D11PixelShader* pPixelShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances); + + void STDMETHODCALLTYPE PSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers); + + void STDMETHODCALLTYPE PSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants); + + void STDMETHODCALLTYPE PSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews); + + void STDMETHODCALLTYPE PSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers); + + void STDMETHODCALLTYPE PSGetShader( + ID3D11PixelShader** ppPixelShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances); + + void STDMETHODCALLTYPE PSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers); + + void STDMETHODCALLTYPE PSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants); + + void STDMETHODCALLTYPE PSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews); + + void STDMETHODCALLTYPE PSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers); + + void STDMETHODCALLTYPE CSSetShader( + ID3D11ComputeShader* pComputeShader, + ID3D11ClassInstance* const* ppClassInstances, + UINT NumClassInstances); + + void STDMETHODCALLTYPE CSSetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers); + + void STDMETHODCALLTYPE CSSetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants); + + void STDMETHODCALLTYPE CSSetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView* const* ppShaderResourceViews); + + void STDMETHODCALLTYPE CSSetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers); + + void STDMETHODCALLTYPE CSSetUnorderedAccessViews( + UINT StartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, + const UINT* pUAVInitialCounts); + + void STDMETHODCALLTYPE CSGetShader( + ID3D11ComputeShader** ppComputeShader, + ID3D11ClassInstance** ppClassInstances, + UINT* pNumClassInstances); + + void STDMETHODCALLTYPE CSGetConstantBuffers( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers); + + void STDMETHODCALLTYPE CSGetConstantBuffers1( + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants); + + void STDMETHODCALLTYPE CSGetShaderResources( + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews); + + void STDMETHODCALLTYPE CSGetSamplers( + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers); + + void STDMETHODCALLTYPE CSGetUnorderedAccessViews( + UINT StartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView** ppUnorderedAccessViews); + + void STDMETHODCALLTYPE OMSetRenderTargets( + UINT NumViews, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView); + + void STDMETHODCALLTYPE OMSetRenderTargetsAndUnorderedAccessViews( + UINT NumRTVs, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView, + UINT UAVStartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, + const UINT* pUAVInitialCounts); + + void STDMETHODCALLTYPE OMSetBlendState( + ID3D11BlendState* pBlendState, + const FLOAT BlendFactor[4], + UINT SampleMask); + + void STDMETHODCALLTYPE OMSetDepthStencilState( + ID3D11DepthStencilState* pDepthStencilState, + UINT StencilRef); + + void STDMETHODCALLTYPE OMGetRenderTargets( + UINT NumViews, + ID3D11RenderTargetView** ppRenderTargetViews, + ID3D11DepthStencilView** ppDepthStencilView); + + void STDMETHODCALLTYPE OMGetRenderTargetsAndUnorderedAccessViews( + UINT NumRTVs, + ID3D11RenderTargetView** ppRenderTargetViews, + ID3D11DepthStencilView** ppDepthStencilView, + UINT UAVStartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView** ppUnorderedAccessViews); + + void STDMETHODCALLTYPE OMGetBlendState( + ID3D11BlendState** ppBlendState, + FLOAT BlendFactor[4], + UINT* pSampleMask); + + void STDMETHODCALLTYPE OMGetDepthStencilState( + ID3D11DepthStencilState** ppDepthStencilState, + UINT* pStencilRef); + + void STDMETHODCALLTYPE RSSetState( + ID3D11RasterizerState* pRasterizerState); + + void STDMETHODCALLTYPE RSSetViewports( + UINT NumViewports, + const D3D11_VIEWPORT* pViewports); + + void STDMETHODCALLTYPE RSSetScissorRects( + UINT NumRects, + const D3D11_RECT* pRects); + + void STDMETHODCALLTYPE RSGetState( + ID3D11RasterizerState** ppRasterizerState); + + void STDMETHODCALLTYPE RSGetViewports( + UINT* pNumViewports, + D3D11_VIEWPORT* pViewports); + + void STDMETHODCALLTYPE RSGetScissorRects( + UINT* pNumRects, + D3D11_RECT* pRects); + + void STDMETHODCALLTYPE SOSetTargets( + UINT NumBuffers, + ID3D11Buffer* const* ppSOTargets, + const UINT* pOffsets); + + void STDMETHODCALLTYPE SOGetTargets( + UINT NumBuffers, + ID3D11Buffer** ppSOTargets); + + void STDMETHODCALLTYPE SOGetTargetsWithOffsets( + UINT NumBuffers, + ID3D11Buffer** ppSOTargets, + UINT* pOffsets); + + BOOL STDMETHODCALLTYPE IsAnnotationEnabled(); + + void STDMETHODCALLTYPE SetMarkerInt( + LPCWSTR pLabel, + INT Data); + + void STDMETHODCALLTYPE BeginEventInt( + LPCWSTR pLabel, + INT Data); + + void STDMETHODCALLTYPE EndEvent(); + + void STDMETHODCALLTYPE GetHardwareProtectionState( + BOOL* pHwProtectionEnable); + + void STDMETHODCALLTYPE SetHardwareProtectionState( + BOOL HwProtectionEnable); + + void STDMETHODCALLTYPE TransitionSurfaceLayout( + IDXGIVkInteropSurface* pSurface, + const VkImageSubresourceRange* pSubresources, + VkImageLayout OldLayout, + VkImageLayout NewLayout); + + D3D10DeviceLock LockContext() { + return m_multithread.AcquireLock(); + } + + protected: + + D3D11DeviceContextExt m_contextExt; + D3D11UserDefinedAnnotation m_annotation; + D3D10Multithread m_multithread; + + Rc<DxvkDevice> m_device; + Rc<DxvkDataBuffer> m_updateBuffer; + + DxvkCsChunkFlags m_csFlags; + DxvkCsChunkRef m_csChunk; + + D3D11ContextState m_state; + D3D11CmdData* m_cmdData; + + void ApplyInputLayout(); + + void ApplyPrimitiveTopology(); + + void ApplyBlendState(); + + void ApplyBlendFactor(); + + void ApplyDepthStencilState(); + + void ApplyStencilRef(); + + void ApplyRasterizerState(); + + void ApplyViewportState(); + + template<DxbcProgramType ShaderStage> + void BindShader( + const D3D11CommonShader* pShaderModule); + + void BindFramebuffer(); + + void BindDrawBuffers( + D3D11Buffer* pBufferForArgs, + D3D11Buffer* pBufferForCount); + + void BindVertexBuffer( + UINT Slot, + D3D11Buffer* pBuffer, + UINT Offset, + UINT Stride); + + void BindIndexBuffer( + D3D11Buffer* pBuffer, + UINT Offset, + DXGI_FORMAT Format); + + void BindXfbBuffer( + UINT Slot, + D3D11Buffer* pBuffer, + UINT Offset); + + void BindConstantBuffer( + UINT Slot, + D3D11Buffer* pBuffer, + UINT Offset, + UINT Length); + + void BindSampler( + UINT Slot, + D3D11SamplerState* pSampler); + + void BindShaderResource( + UINT Slot, + D3D11ShaderResourceView* pResource); + + void BindUnorderedAccessView( + UINT UavSlot, + D3D11UnorderedAccessView* pUav, + UINT CtrSlot, + UINT Counter); + + void CopyBuffer( + D3D11Buffer* pDstBuffer, + VkDeviceSize DstOffset, + D3D11Buffer* pSrcBuffer, + VkDeviceSize SrcOffset, + VkDeviceSize ByteCount); + + void CopyImage( + D3D11CommonTexture* pDstTexture, + const VkImageSubresourceLayers* pDstLayers, + VkOffset3D DstOffset, + D3D11CommonTexture* pSrcTexture, + const VkImageSubresourceLayers* pSrcLayers, + VkOffset3D SrcOffset, + VkExtent3D SrcExtent); + + void DiscardBuffer( + ID3D11Resource* pResource); + + void DiscardTexture( + ID3D11Resource* pResource, + UINT Subresource); + + void UpdateImage( + D3D11CommonTexture* pDstTexture, + const VkImageSubresource* pDstSubresource, + VkOffset3D DstOffset, + VkExtent3D DstExtent, + DxvkBufferSlice StagingBuffer); + + void SetDrawBuffers( + ID3D11Buffer* pBufferForArgs, + ID3D11Buffer* pBufferForCount); + + template<DxbcProgramType ShaderStage> + void SetConstantBuffers( + D3D11ConstantBufferBindings& Bindings, + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers); + + template<DxbcProgramType ShaderStage> + void SetConstantBuffers1( + D3D11ConstantBufferBindings& Bindings, + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer* const* ppConstantBuffers, + const UINT* pFirstConstant, + const UINT* pNumConstants); + + template<DxbcProgramType ShaderStage> + void SetSamplers( + D3D11SamplerBindings& Bindings, + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState* const* ppSamplers); + + template<DxbcProgramType ShaderStage> + void SetShaderResources( + D3D11ShaderResourceBindings& Bindings, + UINT StartSlot, + UINT NumResources, + ID3D11ShaderResourceView* const* ppResources); + + void GetConstantBuffers( + const D3D11ConstantBufferBindings& Bindings, + UINT StartSlot, + UINT NumBuffers, + ID3D11Buffer** ppConstantBuffers, + UINT* pFirstConstant, + UINT* pNumConstants); + + void GetShaderResources( + const D3D11ShaderResourceBindings& Bindings, + UINT StartSlot, + UINT NumViews, + ID3D11ShaderResourceView** ppShaderResourceViews); + + void GetSamplers( + const D3D11SamplerBindings& Bindings, + UINT StartSlot, + UINT NumSamplers, + ID3D11SamplerState** ppSamplers); + + void ResetState(); + + void RestoreState(); + + template<DxbcProgramType Stage> + void RestoreConstantBuffers( + D3D11ConstantBufferBindings& Bindings); + + template<DxbcProgramType Stage> + void RestoreSamplers( + D3D11SamplerBindings& Bindings); + + template<DxbcProgramType Stage> + void RestoreShaderResources( + D3D11ShaderResourceBindings& Bindings); + + template<DxbcProgramType Stage> + void RestoreUnorderedAccessViews( + D3D11UnorderedAccessBindings& Bindings); + + bool TestRtvUavHazards( + UINT NumRTVs, + ID3D11RenderTargetView* const* ppRTVs, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUAVs); + + template<DxbcProgramType ShaderStage> + bool TestSrvHazards( + D3D11ShaderResourceView* pView); + + template<DxbcProgramType ShaderStage, typename T> + void ResolveSrvHazards( + T* pView, + D3D11ShaderResourceBindings& Bindings); + + template<typename T> + void ResolveCsSrvHazards( + T* pView); + + template<typename T> + void ResolveOmSrvHazards( + T* pView); + + bool ResolveOmRtvHazards( + D3D11UnorderedAccessView* pView); + + void ResolveOmUavHazards( + D3D11RenderTargetView* pView); + + bool ValidateRenderTargets( + UINT NumViews, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView); + + VkClearValue ConvertColorValue( + const FLOAT Color[4], + const DxvkFormatInfo* pFormatInfo); + + DxvkDataSlice AllocUpdateBufferSlice(size_t Size); + + DxvkBufferSlice AllocStagingBuffer( + VkDeviceSize Size); + + DxvkCsChunkRef AllocCsChunk(); + + static void InitDefaultPrimitiveTopology( + DxvkInputAssemblyState* pIaState); + + static void InitDefaultRasterizerState( + DxvkRasterizerState* pRsState); + + static void InitDefaultDepthStencilState( + DxvkDepthStencilState* pDsState); + + static void InitDefaultBlendState( + DxvkBlendMode* pCbState, + DxvkLogicOpState* pLoState, + DxvkMultisampleState* pMsState, + UINT SampleMask); + + template<typename T> + const D3D11CommonShader* GetCommonShader(T* pShader) const { + return pShader != nullptr ? pShader->GetCommonShader() : nullptr; + } + + static uint32_t GetIndirectCommandStride(const D3D11CmdDrawIndirectData* cmdData, uint32_t offset, uint32_t minStride) { + if (likely(cmdData->stride)) + return cmdData->offset + cmdData->count * cmdData->stride == offset ? cmdData->stride : 0; + + uint32_t stride = offset - cmdData->offset; + return stride >= minStride && stride <= 32 ? stride : 0; + } + + static bool ValidateDrawBufferSize(ID3D11Buffer* pBuffer, UINT Offset, UINT Size) { + UINT bufferSize = 0; + + if (likely(pBuffer != nullptr)) + bufferSize = static_cast<D3D11Buffer*>(pBuffer)->Desc()->ByteWidth; + + return bufferSize >= Offset + Size; + } + + template<typename Cmd> + void EmitCs(Cmd&& command) { + m_cmdData = nullptr; + + if (unlikely(!m_csChunk->push(command))) { + EmitCsChunk(std::move(m_csChunk)); + + m_csChunk = AllocCsChunk(); + m_csChunk->push(command); + } + } + + template<typename M, typename Cmd, typename... Args> + M* EmitCsCmd(Cmd&& command, Args&&... args) { + M* data = m_csChunk->pushCmd<M, Cmd, Args...>( + command, std::forward<Args>(args)...); + + if (unlikely(!data)) { + EmitCsChunk(std::move(m_csChunk)); + + m_csChunk = AllocCsChunk(); + data = m_csChunk->pushCmd<M, Cmd, Args...>( + command, std::forward<Args>(args)...); + } + + m_cmdData = data; + return data; + } + + void FlushCsChunk() { + if (likely(!m_csChunk->empty())) { + EmitCsChunk(std::move(m_csChunk)); + m_csChunk = AllocCsChunk(); + m_cmdData = nullptr; + } + } + + virtual void EmitCsChunk(DxvkCsChunkRef&& chunk) = 0; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.cpp new file mode 100644 index 00000000..1ac44b06 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.cpp @@ -0,0 +1,383 @@ +#include "d3d11_context_def.h" +#include "d3d11_device.h" + +namespace dxvk { + + D3D11DeferredContext::D3D11DeferredContext( + D3D11Device* pParent, + const Rc<DxvkDevice>& Device, + UINT ContextFlags) + : D3D11DeviceContext(pParent, Device, GetCsChunkFlags(pParent)), + m_contextFlags(ContextFlags), + m_commandList (CreateCommandList()) { + ClearState(); + } + + + D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE D3D11DeferredContext::GetType() { + return D3D11_DEVICE_CONTEXT_DEFERRED; + } + + + UINT STDMETHODCALLTYPE D3D11DeferredContext::GetContextFlags() { + return m_contextFlags; + } + + + HRESULT STDMETHODCALLTYPE D3D11DeferredContext::GetData( + ID3D11Asynchronous* pAsync, + void* pData, + UINT DataSize, + UINT GetDataFlags) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11: GetData called on a deferred context"); + + return DXGI_ERROR_INVALID_CALL; + } + + + void STDMETHODCALLTYPE D3D11DeferredContext::Begin( + ID3D11Asynchronous* pAsync) { + D3D10DeviceLock lock = LockContext(); + + if (unlikely(!pAsync)) + return; + + Com<D3D11Query, false> query(static_cast<D3D11Query*>(pAsync)); + + if (unlikely(!query->IsScoped())) + return; + + auto entry = std::find( + m_queriesBegun.begin(), + m_queriesBegun.end(), query); + + if (unlikely(entry != m_queriesBegun.end())) + return; + + EmitCs([cQuery = query] + (DxvkContext* ctx) { + cQuery->Begin(ctx); + }); + + m_queriesBegun.push_back(std::move(query)); + } + + + void STDMETHODCALLTYPE D3D11DeferredContext::End( + ID3D11Asynchronous* pAsync) { + D3D10DeviceLock lock = LockContext(); + + if (unlikely(!pAsync)) + return; + + Com<D3D11Query, false> query(static_cast<D3D11Query*>(pAsync)); + + if (query->IsScoped()) { + auto entry = std::find( + m_queriesBegun.begin(), + m_queriesBegun.end(), query); + + if (likely(entry != m_queriesBegun.end())) { + m_queriesBegun.erase(entry); + } else { + EmitCs([cQuery = query] + (DxvkContext* ctx) { + cQuery->Begin(ctx); + }); + } + } + + m_commandList->AddQuery(query.ptr()); + + EmitCs([cQuery = std::move(query)] + (DxvkContext* ctx) { + cQuery->End(ctx); + }); + } + + + void STDMETHODCALLTYPE D3D11DeferredContext::Flush() { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11: Flush called on a deferred context"); + } + + + void STDMETHODCALLTYPE D3D11DeferredContext::Flush1( + D3D11_CONTEXT_TYPE ContextType, + HANDLE hEvent) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11: Flush1 called on a deferred context"); + } + + + HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Signal( + ID3D11Fence* pFence, + UINT64 Value) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11: Signal called on a deferred context"); + + return DXGI_ERROR_INVALID_CALL; + } + + + HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Wait( + ID3D11Fence* pFence, + UINT64 Value) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11: Wait called on a deferred context"); + + return DXGI_ERROR_INVALID_CALL; + } + + + void STDMETHODCALLTYPE D3D11DeferredContext::ExecuteCommandList( + ID3D11CommandList* pCommandList, + BOOL RestoreContextState) { + D3D10DeviceLock lock = LockContext(); + + FlushCsChunk(); + + static_cast<D3D11CommandList*>(pCommandList)->EmitToCommandList(m_commandList.ptr()); + + if (RestoreContextState) + RestoreState(); + else + ClearState(); + } + + + HRESULT STDMETHODCALLTYPE D3D11DeferredContext::FinishCommandList( + BOOL RestoreDeferredContextState, + ID3D11CommandList **ppCommandList) { + D3D10DeviceLock lock = LockContext(); + + FinalizeQueries(); + FlushCsChunk(); + + if (ppCommandList != nullptr) + *ppCommandList = m_commandList.ref(); + m_commandList = CreateCommandList(); + + if (RestoreDeferredContextState) + RestoreState(); + else + ClearState(); + + m_mappedResources.clear(); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Map( + ID3D11Resource* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource) { + D3D10DeviceLock lock = LockContext(); + + if (unlikely(!pResource || !pMappedResource)) + return E_INVALIDARG; + + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + if (MapType == D3D11_MAP_WRITE_DISCARD) { + D3D11DeferredContextMapEntry entry; + + HRESULT status = resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER + ? MapBuffer(pResource, MapType, MapFlags, &entry) + : MapImage (pResource, Subresource, MapType, MapFlags, &entry); + + if (unlikely(FAILED(status))) { + *pMappedResource = D3D11_MAPPED_SUBRESOURCE(); + return status; + } + + // Adding a new map entry actually overrides the + // old one in practice because the lookup function + // scans the array in reverse order + m_mappedResources.push_back(std::move(entry)); + + // Fill mapped resource structure + pMappedResource->pData = entry.MapPointer; + pMappedResource->RowPitch = entry.RowPitch; + pMappedResource->DepthPitch = entry.DepthPitch; + return S_OK; + } else if (MapType == D3D11_MAP_WRITE_NO_OVERWRITE) { + // The resource must be mapped with D3D11_MAP_WRITE_DISCARD + // before it can be mapped with D3D11_MAP_WRITE_NO_OVERWRITE. + auto entry = FindMapEntry(pResource, Subresource); + + if (unlikely(entry == m_mappedResources.rend())) { + *pMappedResource = D3D11_MAPPED_SUBRESOURCE(); + return E_INVALIDARG; + } + + // Return same memory region as earlier + entry->MapType = D3D11_MAP_WRITE_NO_OVERWRITE; + + pMappedResource->pData = entry->MapPointer; + pMappedResource->RowPitch = entry->RowPitch; + pMappedResource->DepthPitch = entry->DepthPitch; + return S_OK; + } else { + // Not allowed on deferred contexts + *pMappedResource = D3D11_MAPPED_SUBRESOURCE(); + return E_INVALIDARG; + } + } + + + void STDMETHODCALLTYPE D3D11DeferredContext::Unmap( + ID3D11Resource* pResource, + UINT Subresource) { + // No-op, updates are committed in Map + } + + + void STDMETHODCALLTYPE D3D11DeferredContext::SwapDeviceContextState( + ID3DDeviceContextState* pState, + ID3DDeviceContextState** ppPreviousState) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11: SwapDeviceContextState called on a deferred context"); + } + + + HRESULT D3D11DeferredContext::MapBuffer( + ID3D11Resource* pResource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11DeferredContextMapEntry* pMapEntry) { + D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource); + + if (unlikely(pBuffer->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) { + Logger::err("D3D11: Cannot map a device-local buffer"); + return E_INVALIDARG; + } + + pMapEntry->pResource = pResource; + pMapEntry->Subresource = 0; + pMapEntry->MapType = D3D11_MAP_WRITE_DISCARD; + pMapEntry->RowPitch = pBuffer->Desc()->ByteWidth; + pMapEntry->DepthPitch = pBuffer->Desc()->ByteWidth; + + if (likely(m_csFlags.test(DxvkCsChunkFlag::SingleUse))) { + // For resources that cannot be written by the GPU, + // we may write to the buffer resource directly and + // just swap in the buffer slice as needed. + auto bufferSlice = pBuffer->AllocSlice(); + pMapEntry->MapPointer = bufferSlice.mapPtr; + + EmitCs([ + cDstBuffer = pBuffer->GetBuffer(), + cPhysSlice = bufferSlice + ] (DxvkContext* ctx) { + ctx->invalidateBuffer(cDstBuffer, cPhysSlice); + }); + } else { + // For GPU-writable resources, we need a data slice + // to perform the update operation at execution time. + auto dataSlice = AllocUpdateBufferSlice(pBuffer->Desc()->ByteWidth); + pMapEntry->MapPointer = dataSlice.ptr(); + + EmitCs([ + cDstBuffer = pBuffer->GetBuffer(), + cDataSlice = dataSlice + ] (DxvkContext* ctx) { + DxvkBufferSliceHandle slice = cDstBuffer->allocSlice(); + std::memcpy(slice.mapPtr, cDataSlice.ptr(), cDataSlice.length()); + ctx->invalidateBuffer(cDstBuffer, slice); + }); + } + + return S_OK; + } + + + HRESULT D3D11DeferredContext::MapImage( + ID3D11Resource* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11DeferredContextMapEntry* pMapEntry) { + D3D11CommonTexture* pTexture = GetCommonTexture(pResource); + + if (unlikely(pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) { + Logger::err("D3D11: Cannot map a device-local image"); + return E_INVALIDARG; + } + + if (unlikely(Subresource >= pTexture->CountSubresources())) + return E_INVALIDARG; + + VkFormat packedFormat = pTexture->GetPackedFormat(); + + auto formatInfo = imageFormatInfo(packedFormat); + auto subresource = pTexture->GetSubresourceFromIndex( + formatInfo->aspectMask, Subresource); + + VkExtent3D levelExtent = pTexture->MipLevelExtent(subresource.mipLevel); + + auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, Subresource); + auto dataSlice = AllocStagingBuffer(util::computeImageDataSize(packedFormat, levelExtent)); + + pMapEntry->pResource = pResource; + pMapEntry->Subresource = Subresource; + pMapEntry->MapType = D3D11_MAP_WRITE_DISCARD; + pMapEntry->RowPitch = layout.RowPitch; + pMapEntry->DepthPitch = layout.DepthPitch; + pMapEntry->MapPointer = dataSlice.mapPtr(0); + + UpdateImage(pTexture, &subresource, + VkOffset3D { 0, 0, 0 }, levelExtent, + std::move(dataSlice)); + return S_OK; + } + + + void D3D11DeferredContext::FinalizeQueries() { + for (auto& query : m_queriesBegun) { + m_commandList->AddQuery(query.ptr()); + + EmitCs([cQuery = std::move(query)] + (DxvkContext* ctx) { + cQuery->End(ctx); + }); + } + + m_queriesBegun.clear(); + } + + + Com<D3D11CommandList> D3D11DeferredContext::CreateCommandList() { + return new D3D11CommandList(m_parent, m_contextFlags); + } + + + void D3D11DeferredContext::EmitCsChunk(DxvkCsChunkRef&& chunk) { + m_commandList->AddChunk(std::move(chunk)); + } + + + DxvkCsChunkFlags D3D11DeferredContext::GetCsChunkFlags( + D3D11Device* pDevice) { + return pDevice->GetOptions()->dcSingleUseMode + ? DxvkCsChunkFlags(DxvkCsChunkFlag::SingleUse) + : DxvkCsChunkFlags(); + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.h new file mode 100644 index 00000000..bdfcf441 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.h @@ -0,0 +1,131 @@ +#pragma once + +#include "d3d11_buffer.h" +#include "d3d11_cmdlist.h" +#include "d3d11_context.h" +#include "d3d11_texture.h" + +#include <algorithm> +#include <vector> + +namespace dxvk { + + struct D3D11DeferredContextMapEntry { + Com<ID3D11Resource> pResource; + UINT Subresource; + D3D11_MAP MapType; + UINT RowPitch; + UINT DepthPitch; + void* MapPointer; + }; + + class D3D11DeferredContext : public D3D11DeviceContext { + + public: + + D3D11DeferredContext( + D3D11Device* pParent, + const Rc<DxvkDevice>& Device, + UINT ContextFlags); + + D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE GetType(); + + UINT STDMETHODCALLTYPE GetContextFlags(); + + HRESULT STDMETHODCALLTYPE GetData( + ID3D11Asynchronous* pAsync, + void* pData, + UINT DataSize, + UINT GetDataFlags); + + void STDMETHODCALLTYPE Begin( + ID3D11Asynchronous* pAsync); + + void STDMETHODCALLTYPE End( + ID3D11Asynchronous* pAsync); + + void STDMETHODCALLTYPE Flush(); + + void STDMETHODCALLTYPE Flush1( + D3D11_CONTEXT_TYPE ContextType, + HANDLE hEvent); + + HRESULT STDMETHODCALLTYPE Signal( + ID3D11Fence* pFence, + UINT64 Value); + + HRESULT STDMETHODCALLTYPE Wait( + ID3D11Fence* pFence, + UINT64 Value); + + void STDMETHODCALLTYPE ExecuteCommandList( + ID3D11CommandList* pCommandList, + BOOL RestoreContextState); + + HRESULT STDMETHODCALLTYPE FinishCommandList( + BOOL RestoreDeferredContextState, + ID3D11CommandList** ppCommandList); + + HRESULT STDMETHODCALLTYPE Map( + ID3D11Resource* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource); + + void STDMETHODCALLTYPE Unmap( + ID3D11Resource* pResource, + UINT Subresource); + + void STDMETHODCALLTYPE SwapDeviceContextState( + ID3DDeviceContextState* pState, + ID3DDeviceContextState** ppPreviousState); + + private: + + const UINT m_contextFlags; + + // Command list that we're recording + Com<D3D11CommandList> m_commandList; + + // Info about currently mapped (sub)resources. Using a vector + // here is reasonable since there will usually only be a small + // number of mapped resources per command list. + std::vector<D3D11DeferredContextMapEntry> m_mappedResources; + + // Begun and ended queries, will also be stored in command list + std::vector<Com<D3D11Query, false>> m_queriesBegun; + + HRESULT MapBuffer( + ID3D11Resource* pResource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11DeferredContextMapEntry* pMapEntry); + + HRESULT MapImage( + ID3D11Resource* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11DeferredContextMapEntry* pMapEntry); + + void FinalizeQueries(); + + Com<D3D11CommandList> CreateCommandList(); + + void EmitCsChunk(DxvkCsChunkRef&& chunk); + + static DxvkCsChunkFlags GetCsChunkFlags( + D3D11Device* pDevice); + + auto FindMapEntry(ID3D11Resource* pResource, UINT Subresource) { + return std::find_if(m_mappedResources.rbegin(), m_mappedResources.rend(), + [pResource, Subresource] (const D3D11DeferredContextMapEntry& entry) { + return entry.pResource == pResource + && entry.Subresource == Subresource; + }); + } + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.cpp new file mode 100644 index 00000000..c892f7ef --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.cpp @@ -0,0 +1,198 @@ +#include <vector> +#include <utility> +#include <cstring> + +#include "d3d11_device.h" +#include "d3d11_context.h" +#include "d3d11_cuda.h" + +#include "../util/log/log.h" + +namespace dxvk { + + D3D11DeviceContextExt::D3D11DeviceContextExt( + D3D11DeviceContext* pContext) + : m_ctx(pContext) { + + } + + + ULONG STDMETHODCALLTYPE D3D11DeviceContextExt::AddRef() { + return m_ctx->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11DeviceContextExt::Release() { + return m_ctx->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11DeviceContextExt::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_ctx->QueryInterface(riid, ppvObject); + } + + + void STDMETHODCALLTYPE D3D11DeviceContextExt::MultiDrawIndirect( + UINT DrawCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs) { + D3D10DeviceLock lock = m_ctx->LockContext(); + m_ctx->SetDrawBuffers(pBufferForArgs, nullptr); + + m_ctx->EmitCs([ + cCount = DrawCount, + cOffset = ByteOffsetForArgs, + cStride = ByteStrideForArgs + ] (DxvkContext* ctx) { + ctx->drawIndirect(cOffset, cCount, cStride); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContextExt::MultiDrawIndexedIndirect( + UINT DrawCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs) { + D3D10DeviceLock lock = m_ctx->LockContext(); + m_ctx->SetDrawBuffers(pBufferForArgs, nullptr); + + m_ctx->EmitCs([ + cCount = DrawCount, + cOffset = ByteOffsetForArgs, + cStride = ByteStrideForArgs + ] (DxvkContext* ctx) { + ctx->drawIndexedIndirect(cOffset, cCount, cStride); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContextExt::MultiDrawIndirectCount( + UINT MaxDrawCount, + ID3D11Buffer* pBufferForCount, + UINT ByteOffsetForCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs) { + D3D10DeviceLock lock = m_ctx->LockContext(); + m_ctx->SetDrawBuffers(pBufferForArgs, pBufferForCount); + + m_ctx->EmitCs([ + cMaxCount = MaxDrawCount, + cArgOffset = ByteOffsetForArgs, + cCntOffset = ByteOffsetForCount, + cStride = ByteStrideForArgs + ] (DxvkContext* ctx) { + ctx->drawIndirectCount(cArgOffset, cCntOffset, cMaxCount, cStride); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContextExt::MultiDrawIndexedIndirectCount( + UINT MaxDrawCount, + ID3D11Buffer* pBufferForCount, + UINT ByteOffsetForCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs) { + D3D10DeviceLock lock = m_ctx->LockContext(); + m_ctx->SetDrawBuffers(pBufferForArgs, pBufferForCount); + + m_ctx->EmitCs([ + cMaxCount = MaxDrawCount, + cArgOffset = ByteOffsetForArgs, + cCntOffset = ByteOffsetForCount, + cStride = ByteStrideForArgs + ] (DxvkContext* ctx) { + ctx->drawIndexedIndirectCount(cArgOffset, cCntOffset, cMaxCount, cStride); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContextExt::SetDepthBoundsTest( + BOOL Enable, + FLOAT MinDepthBounds, + FLOAT MaxDepthBounds) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + DxvkDepthBounds db; + db.enableDepthBounds = Enable; + db.minDepthBounds = MinDepthBounds; + db.maxDepthBounds = MaxDepthBounds; + + m_ctx->EmitCs([cDepthBounds = db] (DxvkContext* ctx) { + ctx->setDepthBounds(cDepthBounds); + }); + } + + + void STDMETHODCALLTYPE D3D11DeviceContextExt::SetBarrierControl( + UINT ControlFlags) { + D3D10DeviceLock lock = m_ctx->LockContext(); + DxvkBarrierControlFlags flags; + + if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE) + flags.set(DxvkBarrierControl::IgnoreWriteAfterWrite); + + if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV) + flags.set(DxvkBarrierControl::IgnoreGraphicsBarriers); + + m_ctx->EmitCs([cFlags = flags] (DxvkContext* ctx) { + ctx->setBarrierControl(cFlags); + }); + } + + + bool STDMETHODCALLTYPE D3D11DeviceContextExt::LaunchCubinShaderNVX(IUnknown* hShader, uint32_t GridX, uint32_t GridY, uint32_t GridZ, + const void* pParams, uint32_t ParamSize, void* const* pReadResources, uint32_t NumReadResources, void* const* pWriteResources, uint32_t NumWriteResources) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + CubinShaderWrapper* cubinShader = static_cast<CubinShaderWrapper*>(hShader); + CubinShaderLaunchInfo launchInfo; + + const uint32_t maxResources = NumReadResources + NumWriteResources; + launchInfo.buffers.reserve(maxResources); + launchInfo.images.reserve(maxResources); + + for (uint32_t i = 0; i < NumReadResources; i++) + launchInfo.insertResource(static_cast<ID3D11Resource*>(pReadResources[i]), DxvkAccess::Read); + + for (uint32_t i = 0; i < NumWriteResources; i++) + launchInfo.insertResource(static_cast<ID3D11Resource*>(pWriteResources[i]), DxvkAccess::Write); + + launchInfo.paramSize = ParamSize; + launchInfo.params.resize(launchInfo.paramSize); + std::memcpy(launchInfo.params.data(), pParams, ParamSize); + + launchInfo.cuLaunchConfig[0] = reinterpret_cast<void*>(0x01); // CU_LAUNCH_PARAM_BUFFER_POINTER + launchInfo.cuLaunchConfig[1] = launchInfo.params.data(); + launchInfo.cuLaunchConfig[2] = reinterpret_cast<void*>(0x02); // CU_LAUNCH_PARAM_BUFFER_SIZE + launchInfo.cuLaunchConfig[3] = &launchInfo.paramSize; // yes, this actually requires a pointer to a size_t containing the parameter size + launchInfo.cuLaunchConfig[4] = reinterpret_cast<void*>(0x00); // CU_LAUNCH_PARAM_END + + launchInfo.nvxLaunchInfo.function = cubinShader->cuFunction(); + launchInfo.nvxLaunchInfo.gridDimX = GridX; + launchInfo.nvxLaunchInfo.gridDimY = GridY; + launchInfo.nvxLaunchInfo.gridDimZ = GridZ; + launchInfo.nvxLaunchInfo.blockDimX = cubinShader->blockDim().width; + launchInfo.nvxLaunchInfo.blockDimY = cubinShader->blockDim().height; + launchInfo.nvxLaunchInfo.blockDimZ = cubinShader->blockDim().depth; + launchInfo.nvxLaunchInfo.sharedMemBytes = 0; + launchInfo.nvxLaunchInfo.paramCount = 0; + launchInfo.nvxLaunchInfo.pParams = nullptr; + launchInfo.nvxLaunchInfo.extraCount = 1; + launchInfo.nvxLaunchInfo.pExtras = launchInfo.cuLaunchConfig.data(); + + launchInfo.shader = cubinShader; + + /* Need to capture by value in case this gets called from a deferred context */ + m_ctx->EmitCs([cLaunchInfo = std::move(launchInfo)] (DxvkContext* ctx) { + ctx->launchCuKernelNVX(cLaunchInfo.nvxLaunchInfo, cLaunchInfo.buffers, cLaunchInfo.images); + }); + + return true; + } +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.h new file mode 100644 index 00000000..2109a0de --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.h @@ -0,0 +1,78 @@ +#pragma once + +#include "d3d11_interfaces.h" + +namespace dxvk { + + class D3D11DeviceContext; + + class D3D11DeviceContextExt : public ID3D11VkExtContext1 { + + public: + + D3D11DeviceContextExt( + D3D11DeviceContext* pContext); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void STDMETHODCALLTYPE MultiDrawIndirect( + UINT DrawCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs); + + void STDMETHODCALLTYPE MultiDrawIndexedIndirect( + UINT DrawCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs); + + void STDMETHODCALLTYPE MultiDrawIndirectCount( + UINT MaxDrawCount, + ID3D11Buffer* pBufferForCount, + UINT ByteOffsetForCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs); + + void STDMETHODCALLTYPE MultiDrawIndexedIndirectCount( + UINT MaxDrawCount, + ID3D11Buffer* pBufferForCount, + UINT ByteOffsetForCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs); + + void STDMETHODCALLTYPE SetDepthBoundsTest( + BOOL Enable, + FLOAT MinDepthBounds, + FLOAT MaxDepthBounds); + + void STDMETHODCALLTYPE SetBarrierControl( + UINT ControlFlags); + + bool STDMETHODCALLTYPE LaunchCubinShaderNVX( + IUnknown* hShader, + uint32_t GridX, + uint32_t GridY, + uint32_t GridZ, + const void* pParams, + uint32_t paramSize, + void* const* pReadResources, + uint32_t NumReadResources, + void* const* pWriteResources, + uint32_t NumWriteResources); + + private: + + D3D11DeviceContext* m_ctx; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.cpp new file mode 100644 index 00000000..3bac02e7 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.cpp @@ -0,0 +1,623 @@ +#include "d3d11_cmdlist.h" +#include "d3d11_context_imm.h" +#include "d3d11_device.h" +#include "d3d11_texture.h" + +constexpr static uint32_t MinFlushIntervalUs = 750; +constexpr static uint32_t IncFlushIntervalUs = 250; +constexpr static uint32_t MaxPendingSubmits = 6; + +namespace dxvk { + + D3D11ImmediateContext::D3D11ImmediateContext( + D3D11Device* pParent, + const Rc<DxvkDevice>& Device) + : D3D11DeviceContext(pParent, Device, DxvkCsChunkFlag::SingleUse), + m_csThread(Device->createContext()), + m_videoContext(this, Device) { + EmitCs([ + cDevice = m_device, + cRelaxedBarriers = pParent->GetOptions()->relaxedBarriers, + cIgnoreGraphicsBarriers = pParent->GetOptions()->ignoreGraphicsBarriers + ] (DxvkContext* ctx) { + ctx->beginRecording(cDevice->createCommandList()); + + DxvkBarrierControlFlags barrierControl; + + if (cRelaxedBarriers) + barrierControl.set(DxvkBarrierControl::IgnoreWriteAfterWrite); + + if (cIgnoreGraphicsBarriers) + barrierControl.set(DxvkBarrierControl::IgnoreGraphicsBarriers); + + ctx->setBarrierControl(barrierControl); + }); + + ClearState(); + } + + + D3D11ImmediateContext::~D3D11ImmediateContext() { + Flush(); + SynchronizeCsThread(); + SynchronizeDevice(); + } + + + HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::QueryInterface(REFIID riid, void** ppvObject) { + if (riid == __uuidof(ID3D11VideoContext)) { + *ppvObject = ref(&m_videoContext); + return S_OK; + } + + return D3D11DeviceContext::QueryInterface(riid, ppvObject); + } + + + D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE D3D11ImmediateContext::GetType() { + return D3D11_DEVICE_CONTEXT_IMMEDIATE; + } + + + UINT STDMETHODCALLTYPE D3D11ImmediateContext::GetContextFlags() { + return 0; + } + + + HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::GetData( + ID3D11Asynchronous* pAsync, + void* pData, + UINT DataSize, + UINT GetDataFlags) { + if (!pAsync || (DataSize && !pData)) + return E_INVALIDARG; + + // Check whether the data size is actually correct + if (DataSize && DataSize != pAsync->GetDataSize()) + return E_INVALIDARG; + + // Passing a non-null pData is actually allowed if + // DataSize is 0, but we should ignore that pointer + pData = DataSize ? pData : nullptr; + + // Get query status directly from the query object + auto query = static_cast<D3D11Query*>(pAsync); + HRESULT hr = query->GetData(pData, GetDataFlags); + + // If we're likely going to spin on the asynchronous object, + // flush the context so that we're keeping the GPU busy. + if (hr == S_FALSE) { + // Don't mark the event query as stalling if the app does + // not intend to spin on it. This reduces flushes on End. + if (!(GetDataFlags & D3D11_ASYNC_GETDATA_DONOTFLUSH)) + query->NotifyStall(); + + // Ignore the DONOTFLUSH flag here as some games will spin + // on queries without ever flushing the context otherwise. + FlushImplicit(FALSE); + } + + return hr; + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::Begin(ID3D11Asynchronous* pAsync) { + D3D10DeviceLock lock = LockContext(); + + if (unlikely(!pAsync)) + return; + + auto query = static_cast<D3D11Query*>(pAsync); + + if (unlikely(!query->DoBegin())) + return; + + EmitCs([cQuery = Com<D3D11Query, false>(query)] + (DxvkContext* ctx) { + cQuery->Begin(ctx); + }); + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::End(ID3D11Asynchronous* pAsync) { + D3D10DeviceLock lock = LockContext(); + + if (unlikely(!pAsync)) + return; + + auto query = static_cast<D3D11Query*>(pAsync); + + if (unlikely(!query->DoEnd())) { + EmitCs([cQuery = Com<D3D11Query, false>(query)] + (DxvkContext* ctx) { + cQuery->Begin(ctx); + }); + } + + EmitCs([cQuery = Com<D3D11Query, false>(query)] + (DxvkContext* ctx) { + cQuery->End(ctx); + }); + + if (unlikely(query->IsEvent())) { + query->NotifyEnd(); + query->IsStalling() + ? Flush() + : FlushImplicit(TRUE); + } + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::Flush() { + Flush1(D3D11_CONTEXT_TYPE_ALL, nullptr); + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::Flush1( + D3D11_CONTEXT_TYPE ContextType, + HANDLE hEvent) { + m_parent->FlushInitContext(); + + if (hEvent) + SignalEvent(hEvent); + + D3D10DeviceLock lock = LockContext(); + + if (m_csIsBusy || !m_csChunk->empty()) { + // Add commands to flush the threaded + // context, then flush the command list + EmitCs([] (DxvkContext* ctx) { + ctx->flushCommandList(); + }); + + FlushCsChunk(); + + // Reset flush timer used for implicit flushes + m_lastFlush = dxvk::high_resolution_clock::now(); + m_csIsBusy = false; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::Signal( + ID3D11Fence* pFence, + UINT64 Value) { + Logger::err("D3D11ImmediateContext::Signal: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::Wait( + ID3D11Fence* pFence, + UINT64 Value) { + Logger::err("D3D11ImmediateContext::Wait: Not implemented"); + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::ExecuteCommandList( + ID3D11CommandList* pCommandList, + BOOL RestoreContextState) { + D3D10DeviceLock lock = LockContext(); + + auto commandList = static_cast<D3D11CommandList*>(pCommandList); + + // Flush any outstanding commands so that + // we don't mess up the execution order + FlushCsChunk(); + + // As an optimization, flush everything if the + // number of pending draw calls is high enough. + FlushImplicit(FALSE); + + // Dispatch command list to the CS thread and + // restore the immediate context's state + commandList->EmitToCsThread(&m_csThread); + + if (RestoreContextState) + RestoreState(); + else + ClearState(); + + // Mark CS thread as busy so that subsequent + // flush operations get executed correctly. + m_csIsBusy = true; + } + + + HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::FinishCommandList( + BOOL RestoreDeferredContextState, + ID3D11CommandList **ppCommandList) { + InitReturnPtr(ppCommandList); + + Logger::err("D3D11: FinishCommandList called on immediate context"); + return DXGI_ERROR_INVALID_CALL; + } + + + HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::Map( + ID3D11Resource* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource) { + D3D10DeviceLock lock = LockContext(); + + if (unlikely(!pResource)) + return E_INVALIDARG; + + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + HRESULT hr; + + if (likely(resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER)) { + hr = MapBuffer( + static_cast<D3D11Buffer*>(pResource), + MapType, MapFlags, pMappedResource); + } else { + hr = MapImage( + GetCommonTexture(pResource), + Subresource, MapType, MapFlags, + pMappedResource); + } + + if (unlikely(FAILED(hr))) + *pMappedResource = D3D11_MAPPED_SUBRESOURCE(); + + return hr; + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::Unmap( + ID3D11Resource* pResource, + UINT Subresource) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + if (unlikely(resourceDim != D3D11_RESOURCE_DIMENSION_BUFFER)) { + D3D10DeviceLock lock = LockContext(); + UnmapImage(GetCommonTexture(pResource), Subresource); + } + } + + void STDMETHODCALLTYPE D3D11ImmediateContext::UpdateSubresource( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch) { + FlushImplicit(FALSE); + + D3D11DeviceContext::UpdateSubresource( + pDstResource, DstSubresource, pDstBox, + pSrcData, SrcRowPitch, SrcDepthPitch); + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::UpdateSubresource1( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch, + UINT CopyFlags) { + FlushImplicit(FALSE); + + D3D11DeviceContext::UpdateSubresource1( + pDstResource, DstSubresource, pDstBox, + pSrcData, SrcRowPitch, SrcDepthPitch, + CopyFlags); + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::OMSetRenderTargets( + UINT NumViews, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView) { + FlushImplicit(TRUE); + + D3D11DeviceContext::OMSetRenderTargets( + NumViews, ppRenderTargetViews, pDepthStencilView); + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::OMSetRenderTargetsAndUnorderedAccessViews( + UINT NumRTVs, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView, + UINT UAVStartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, + const UINT* pUAVInitialCounts) { + FlushImplicit(TRUE); + + D3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews( + NumRTVs, ppRenderTargetViews, pDepthStencilView, + UAVStartSlot, NumUAVs, ppUnorderedAccessViews, + pUAVInitialCounts); + } + + + HRESULT D3D11ImmediateContext::MapBuffer( + D3D11Buffer* pResource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource) { + if (unlikely(!pMappedResource)) + return E_INVALIDARG; + + if (unlikely(pResource->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) { + Logger::err("D3D11: Cannot map a device-local buffer"); + return E_INVALIDARG; + } + + if (MapType == D3D11_MAP_WRITE_DISCARD) { + // Allocate a new backing slice for the buffer and set + // it as the 'new' mapped slice. This assumes that the + // only way to invalidate a buffer is by mapping it. + auto physSlice = pResource->DiscardSlice(); + pMappedResource->pData = physSlice.mapPtr; + pMappedResource->RowPitch = pResource->Desc()->ByteWidth; + pMappedResource->DepthPitch = pResource->Desc()->ByteWidth; + + EmitCs([ + cBuffer = pResource->GetBuffer(), + cBufferSlice = physSlice + ] (DxvkContext* ctx) { + ctx->invalidateBuffer(cBuffer, cBufferSlice); + }); + + return S_OK; + } else { + // Wait until the resource is no longer in use + if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) { + if (!WaitForResource(pResource->GetBuffer(), MapType, MapFlags)) + return DXGI_ERROR_WAS_STILL_DRAWING; + } + + // Use map pointer from previous map operation. This + // way we don't have to synchronize with the CS thread + // if the map mode is D3D11_MAP_WRITE_NO_OVERWRITE. + DxvkBufferSliceHandle physSlice = pResource->GetMappedSlice(); + + pMappedResource->pData = physSlice.mapPtr; + pMappedResource->RowPitch = pResource->Desc()->ByteWidth; + pMappedResource->DepthPitch = pResource->Desc()->ByteWidth; + return S_OK; + } + } + + + HRESULT D3D11ImmediateContext::MapImage( + D3D11CommonTexture* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource) { + const Rc<DxvkImage> mappedImage = pResource->GetImage(); + const Rc<DxvkBuffer> mappedBuffer = pResource->GetMappedBuffer(Subresource); + + auto mapMode = pResource->GetMapMode(); + + if (unlikely(mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) { + Logger::err("D3D11: Cannot map a device-local image"); + return E_INVALIDARG; + } + + if (unlikely(Subresource >= pResource->CountSubresources())) + return E_INVALIDARG; + + if (likely(pMappedResource != nullptr)) { + // Resources with an unknown memory layout cannot return a pointer + if (pResource->Desc()->Usage == D3D11_USAGE_DEFAULT + && pResource->Desc()->TextureLayout == D3D11_TEXTURE_LAYOUT_UNDEFINED) + return E_INVALIDARG; + } else { + if (pResource->Desc()->Usage != D3D11_USAGE_DEFAULT) + return E_INVALIDARG; + } + + VkFormat packedFormat = m_parent->LookupPackedFormat( + pResource->Desc()->Format, pResource->GetFormatMode()).Format; + + auto formatInfo = imageFormatInfo(packedFormat); + void* mapPtr; + + if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) { + // Wait for the resource to become available + if (!WaitForResource(mappedImage, MapType, MapFlags)) + return DXGI_ERROR_WAS_STILL_DRAWING; + + // Query the subresource's memory layout and hope that + // the application respects the returned pitch values. + mapPtr = mappedImage->mapPtr(0); + } else { + if (MapType == D3D11_MAP_WRITE_DISCARD) { + // We do not have to preserve the contents of the + // buffer if the entire image gets discarded. + DxvkBufferSliceHandle physSlice = pResource->DiscardSlice(Subresource); + + EmitCs([ + cImageBuffer = mappedBuffer, + cBufferSlice = physSlice + ] (DxvkContext* ctx) { + ctx->invalidateBuffer(cImageBuffer, cBufferSlice); + }); + + mapPtr = physSlice.mapPtr; + } else { + bool wait = MapType != D3D11_MAP_WRITE_NO_OVERWRITE + || mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; + + // Wait for mapped buffer to become available + if (wait && !WaitForResource(mappedBuffer, MapType, MapFlags)) + return DXGI_ERROR_WAS_STILL_DRAWING; + + mapPtr = pResource->GetMappedSlice(Subresource).mapPtr; + } + } + + // Mark the given subresource as mapped + pResource->SetMapType(Subresource, MapType); + + if (pMappedResource) { + auto layout = pResource->GetSubresourceLayout(formatInfo->aspectMask, Subresource); + pMappedResource->pData = reinterpret_cast<char*>(mapPtr) + layout.Offset; + pMappedResource->RowPitch = layout.RowPitch; + pMappedResource->DepthPitch = layout.DepthPitch; + } + + return S_OK; + } + + + void D3D11ImmediateContext::UnmapImage( + D3D11CommonTexture* pResource, + UINT Subresource) { + D3D11_MAP mapType = pResource->GetMapType(Subresource); + pResource->SetMapType(Subresource, D3D11_MAP(~0u)); + + if (mapType == D3D11_MAP(~0u) + || mapType == D3D11_MAP_READ) + return; + + if (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER) { + // Now that data has been written into the buffer, + // we need to copy its contents into the image + VkImageAspectFlags aspectMask = imageFormatInfo(pResource->GetPackedFormat())->aspectMask; + VkImageSubresource subresource = pResource->GetSubresourceFromIndex(aspectMask, Subresource); + + UpdateImage(pResource, &subresource, VkOffset3D { 0, 0, 0 }, + pResource->MipLevelExtent(subresource.mipLevel), + DxvkBufferSlice(pResource->GetMappedBuffer(Subresource))); + } + } + + + void STDMETHODCALLTYPE D3D11ImmediateContext::SwapDeviceContextState( + ID3DDeviceContextState* pState, + ID3DDeviceContextState** ppPreviousState) { + InitReturnPtr(ppPreviousState); + + if (!pState) + return; + + Com<D3D11DeviceContextState> oldState = std::move(m_stateObject); + Com<D3D11DeviceContextState> newState = static_cast<D3D11DeviceContextState*>(pState); + + if (oldState == nullptr) + oldState = new D3D11DeviceContextState(m_parent); + + if (ppPreviousState) + *ppPreviousState = oldState.ref(); + + m_stateObject = newState; + + oldState->SetState(m_state); + newState->GetState(m_state); + + RestoreState(); + } + + + void D3D11ImmediateContext::SynchronizeCsThread() { + D3D10DeviceLock lock = LockContext(); + + // Dispatch current chunk so that all commands + // recorded prior to this function will be run + FlushCsChunk(); + + if (m_csThread.isBusy()) + m_csThread.synchronize(); + } + + + void D3D11ImmediateContext::SynchronizeDevice() { + m_device->waitForIdle(); + } + + + bool D3D11ImmediateContext::WaitForResource( + const Rc<DxvkResource>& Resource, + D3D11_MAP MapType, + UINT MapFlags) { + // Determine access type to wait for based on map mode + DxvkAccess access = MapType == D3D11_MAP_READ + ? DxvkAccess::Write + : DxvkAccess::Read; + + // Wait for the any pending D3D11 command to be executed + // on the CS thread so that we can determine whether the + // resource is currently in use or not. + if (!Resource->isInUse(access)) + SynchronizeCsThread(); + + if (Resource->isInUse(access)) { + if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) { + // We don't have to wait, but misbehaving games may + // still try to spin on `Map` until the resource is + // idle, so we should flush pending commands + FlushImplicit(FALSE); + return false; + } else { + // Make sure pending commands using the resource get + // executed on the the GPU if we have to wait for it + Flush(); + SynchronizeCsThread(); + + Resource->waitIdle(access); + } + } + + return true; + } + + + void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) { + m_csThread.dispatchChunk(std::move(chunk)); + m_csIsBusy = true; + } + + + void D3D11ImmediateContext::FlushImplicit(BOOL StrongHint) { + // Flush only if the GPU is about to go idle, in + // order to keep the number of submissions low. + uint32_t pending = m_device->pendingSubmissions(); + + if (StrongHint || pending <= MaxPendingSubmits) { + auto now = dxvk::high_resolution_clock::now(); + + uint32_t delay = MinFlushIntervalUs + + IncFlushIntervalUs * pending; + + // Prevent flushing too often in short intervals. + if (now - m_lastFlush >= std::chrono::microseconds(delay)) + Flush(); + } + } + + + void D3D11ImmediateContext::SignalEvent(HANDLE hEvent) { +#ifndef DXVK_NATIVE + uint64_t value = ++m_eventCount; + + if (m_eventSignal == nullptr) + m_eventSignal = new sync::CallbackFence(); + + m_eventSignal->setCallback(value, [hEvent] { + SetEvent(hEvent); + }); + + EmitCs([ + cSignal = m_eventSignal, + cValue = value + ] (DxvkContext* ctx) { + ctx->signal(cSignal, cValue); + }); +#endif + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.h new file mode 100644 index 00000000..8a638da1 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.h @@ -0,0 +1,166 @@ +#pragma once + +#include "../util/util_time.h" + +#ifndef DXVK_NATIVE +#include "../util/sync/sync_signal.h" +#endif + +#include "d3d11_context.h" +#include "d3d11_state_object.h" +#include "d3d11_video.h" + +namespace dxvk { + + class D3D11Buffer; + class D3D11CommonTexture; + + class D3D11ImmediateContext : public D3D11DeviceContext { + friend class D3D11SwapChain; + friend class D3D11VideoContext; + public: + + D3D11ImmediateContext( + D3D11Device* pParent, + const Rc<DxvkDevice>& Device); + ~D3D11ImmediateContext(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE GetType(); + + UINT STDMETHODCALLTYPE GetContextFlags(); + + HRESULT STDMETHODCALLTYPE GetData( + ID3D11Asynchronous* pAsync, + void* pData, + UINT DataSize, + UINT GetDataFlags); + + void STDMETHODCALLTYPE Begin( + ID3D11Asynchronous* pAsync); + + void STDMETHODCALLTYPE End( + ID3D11Asynchronous* pAsync); + + void STDMETHODCALLTYPE Flush(); + + void STDMETHODCALLTYPE Flush1( + D3D11_CONTEXT_TYPE ContextType, + HANDLE hEvent); + + HRESULT STDMETHODCALLTYPE Signal( + ID3D11Fence* pFence, + UINT64 Value); + + HRESULT STDMETHODCALLTYPE Wait( + ID3D11Fence* pFence, + UINT64 Value); + + void STDMETHODCALLTYPE ExecuteCommandList( + ID3D11CommandList* pCommandList, + BOOL RestoreContextState); + + HRESULT STDMETHODCALLTYPE FinishCommandList( + BOOL RestoreDeferredContextState, + ID3D11CommandList **ppCommandList); + + HRESULT STDMETHODCALLTYPE Map( + ID3D11Resource* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource); + + void STDMETHODCALLTYPE Unmap( + ID3D11Resource* pResource, + UINT Subresource); + + void STDMETHODCALLTYPE UpdateSubresource( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch); + + void STDMETHODCALLTYPE UpdateSubresource1( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch, + UINT CopyFlags); + + void STDMETHODCALLTYPE OMSetRenderTargets( + UINT NumViews, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView); + + void STDMETHODCALLTYPE OMSetRenderTargetsAndUnorderedAccessViews( + UINT NumRTVs, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView, + UINT UAVStartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, + const UINT* pUAVInitialCounts); + + void STDMETHODCALLTYPE SwapDeviceContextState( + ID3DDeviceContextState* pState, + ID3DDeviceContextState** ppPreviousState); + + void SynchronizeCsThread(); + + private: + + DxvkCsThread m_csThread; + bool m_csIsBusy = false; + +#ifndef DXVK_NATIVE + Rc<sync::CallbackFence> m_eventSignal; +#endif + uint64_t m_eventCount = 0; + + dxvk::high_resolution_clock::time_point m_lastFlush + = dxvk::high_resolution_clock::now(); + + D3D11VideoContext m_videoContext; + Com<D3D11DeviceContextState> m_stateObject; + + HRESULT MapBuffer( + D3D11Buffer* pResource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource); + + HRESULT MapImage( + D3D11CommonTexture* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource); + + void UnmapImage( + D3D11CommonTexture* pResource, + UINT Subresource); + + void SynchronizeDevice(); + + bool WaitForResource( + const Rc<DxvkResource>& Resource, + D3D11_MAP MapType, + UINT MapFlags); + + void EmitCsChunk(DxvkCsChunkRef&& chunk); + + void FlushImplicit(BOOL StrongHint); + + void SignalEvent(HANDLE hEvent); + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_state.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_state.h new file mode 100644 index 00000000..eca2a3c9 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_state.h @@ -0,0 +1,187 @@ +#pragma once + +#include <array> + +#include "d3d11_buffer.h" +#include "d3d11_input_layout.h" +#include "d3d11_query.h" +#include "d3d11_sampler.h" +#include "d3d11_shader.h" +#include "d3d11_state.h" +#include "d3d11_view_dsv.h" +#include "d3d11_view_rtv.h" +#include "d3d11_view_srv.h" +#include "d3d11_view_uav.h" + +namespace dxvk { + + struct D3D11ConstantBufferBinding { + Com<D3D11Buffer> buffer = nullptr; + UINT constantOffset = 0; + UINT constantCount = 0; + UINT constantBound = 0; + }; + + using D3D11ConstantBufferBindings = std::array< + D3D11ConstantBufferBinding, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT>; + + + using D3D11SamplerBindings = std::array< + D3D11SamplerState*, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT>; + + + struct D3D11ShaderResourceBindings { + std::array<Com<D3D11ShaderResourceView>, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> views = { }; + DxvkBindingSet<D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> hazardous = { }; + }; + + + using D3D11UnorderedAccessBindings = std::array< + Com<D3D11UnorderedAccessView>, D3D11_1_UAV_SLOT_COUNT>; + + + struct D3D11ContextStateVS { + Com<D3D11VertexShader> shader = nullptr; + D3D11ConstantBufferBindings constantBuffers = { }; + D3D11SamplerBindings samplers = { }; + D3D11ShaderResourceBindings shaderResources = { }; + }; + + + struct D3D11ContextStateHS { + Com<D3D11HullShader> shader = nullptr; + D3D11ConstantBufferBindings constantBuffers = { }; + D3D11SamplerBindings samplers = { }; + D3D11ShaderResourceBindings shaderResources = { }; + }; + + + struct D3D11ContextStateDS { + Com<D3D11DomainShader> shader = nullptr; + D3D11ConstantBufferBindings constantBuffers = { }; + D3D11SamplerBindings samplers = { }; + D3D11ShaderResourceBindings shaderResources = { }; + }; + + + struct D3D11ContextStateGS { + Com<D3D11GeometryShader> shader = nullptr; + D3D11ConstantBufferBindings constantBuffers = { }; + D3D11SamplerBindings samplers = { }; + D3D11ShaderResourceBindings shaderResources = { }; + }; + + + struct D3D11ContextStatePS { + Com<D3D11PixelShader> shader = nullptr; + D3D11ConstantBufferBindings constantBuffers = { }; + D3D11SamplerBindings samplers = { }; + D3D11ShaderResourceBindings shaderResources = { }; + D3D11UnorderedAccessBindings unorderedAccessViews = { }; + }; + + + struct D3D11ContextStateCS { + Com<D3D11ComputeShader> shader = nullptr; + D3D11ConstantBufferBindings constantBuffers = { }; + D3D11SamplerBindings samplers = { }; + D3D11ShaderResourceBindings shaderResources = { }; + D3D11UnorderedAccessBindings unorderedAccessViews = { }; + + DxvkBindingSet<D3D11_1_UAV_SLOT_COUNT> uavMask = { }; + }; + + + struct D3D11VertexBufferBinding { + Com<D3D11Buffer> buffer = nullptr; + UINT offset = 0; + UINT stride = 0; + }; + + + struct D3D11IndexBufferBinding { + Com<D3D11Buffer> buffer = nullptr; + UINT offset = 0; + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + }; + + + struct D3D11ContextStateID { + Com<D3D11Buffer> argBuffer = nullptr; + Com<D3D11Buffer> cntBuffer = nullptr; + }; + + + struct D3D11ContextStateIA { + Com<D3D11InputLayout> inputLayout = nullptr; + D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + + std::array<D3D11VertexBufferBinding, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> vertexBuffers = { }; + D3D11IndexBufferBinding indexBuffer = { }; + }; + + + struct D3D11ContextStateOM { + std::array<Com<D3D11RenderTargetView, false>, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT> renderTargetViews = { }; + Com<D3D11DepthStencilView, false> depthStencilView = { }; + + D3D11BlendState* cbState = nullptr; + D3D11DepthStencilState* dsState = nullptr; + + FLOAT blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + UINT sampleMask = 0xFFFFFFFFu; + UINT stencilRef = 0u; + + UINT maxRtv = 0u; + UINT maxUav = 0u; + }; + + + struct D3D11ContextStateRS { + uint32_t numViewports = 0; + uint32_t numScissors = 0; + + std::array<D3D11_VIEWPORT, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> viewports = { }; + std::array<D3D11_RECT, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> scissors = { }; + + D3D11RasterizerState* state = nullptr; + }; + + + struct D3D11ContextSoTarget { + Com<D3D11Buffer> buffer = nullptr; + UINT offset = 0; + }; + + + struct D3D11ContextStateSO { + std::array<D3D11ContextSoTarget, D3D11_SO_BUFFER_SLOT_COUNT> targets = { }; + }; + + + struct D3D11ContextStatePR { + Com<D3D11Query> predicateObject = nullptr; + BOOL predicateValue = FALSE; + }; + + + /** + * \brief Context state + */ + struct D3D11ContextState { + D3D11ContextStateCS cs; + D3D11ContextStateDS ds; + D3D11ContextStateGS gs; + D3D11ContextStateHS hs; + D3D11ContextStatePS ps; + D3D11ContextStateVS vs; + + D3D11ContextStateID id; + D3D11ContextStateIA ia; + D3D11ContextStateOM om; + D3D11ContextStateRS rs; + D3D11ContextStateSO so; + D3D11ContextStatePR pr; + }; + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.cpp new file mode 100644 index 00000000..4a31d347 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.cpp @@ -0,0 +1,51 @@ +#include "d3d11_cuda.h" + +namespace dxvk { + + CubinShaderWrapper::CubinShaderWrapper(const Rc<dxvk::DxvkDevice>& dxvkDevice, VkCuModuleNVX cuModule, VkCuFunctionNVX cuFunction, VkExtent3D blockDim) + : m_dxvkDevice(dxvkDevice), m_module(cuModule), m_function(cuFunction), m_blockDim(blockDim) { }; + + + CubinShaderWrapper::~CubinShaderWrapper() { + VkDevice vkDevice = m_dxvkDevice->handle(); + m_dxvkDevice->vkd()->vkDestroyCuFunctionNVX(vkDevice, m_function, nullptr); + m_dxvkDevice->vkd()->vkDestroyCuModuleNVX(vkDevice, m_module, nullptr); + }; + + + HRESULT STDMETHODCALLTYPE CubinShaderWrapper::QueryInterface(REFIID riid, void **ppvObject) { + if (riid == __uuidof(IUnknown)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("CubinShaderWrapper::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void CubinShaderLaunchInfo::insertResource(ID3D11Resource* pResource, DxvkAccessFlags access) { + auto img = GetCommonTexture(pResource); + auto buf = GetCommonBuffer(pResource); + + if (img) + insertUniqueResource(images, img->GetImage(), access); + if (buf) + insertUniqueResource(buffers, buf->GetBuffer(), access); + } + + + template<typename T> + void CubinShaderLaunchInfo::insertUniqueResource(std::vector<std::pair<T, DxvkAccessFlags>>& list, const T& resource, DxvkAccessFlags access) { + for (auto& entry : list) { + if (entry.first == resource) { + entry.second.set(access); + return; + } + } + + list.push_back({ resource, access }); + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.h new file mode 100644 index 00000000..a9fcdf4b --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.h @@ -0,0 +1,83 @@ +#pragma once + +#include <utility> +#include <vector> + +#include "../dxvk/dxvk_resource.h" + +#include "../util/com/com_guid.h" +#include "../util/com/com_object.h" + +#include "d3d11_buffer.h" +#include "d3d11_texture.h" + +namespace dxvk { + + class CubinShaderWrapper : public ComObject<IUnknown> { + + public: + + CubinShaderWrapper(const Rc<dxvk::DxvkDevice>& dxvkDevice, VkCuModuleNVX cuModule, VkCuFunctionNVX cuFunction, VkExtent3D blockDim); + ~CubinShaderWrapper(); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + VkCuModuleNVX cuModule() const { + return m_module; + } + + VkCuFunctionNVX cuFunction() const { + return m_function; + } + + VkExtent3D blockDim() const { + return m_blockDim; + } + + private: + + Rc<DxvkDevice> m_dxvkDevice; + VkCuModuleNVX m_module; + VkCuFunctionNVX m_function; + VkExtent3D m_blockDim; + + }; + + + struct CubinShaderLaunchInfo { + + CubinShaderLaunchInfo() = default; + + CubinShaderLaunchInfo(CubinShaderLaunchInfo&& other) { + shader = std::move(other.shader); + params = std::move(other.params); + paramSize = std::move(other.paramSize); + nvxLaunchInfo = std::move(other.nvxLaunchInfo); + cuLaunchConfig = other.cuLaunchConfig; + buffers = std::move(other.buffers); + images = std::move(other.images); + other.cuLaunchConfig[1] = nullptr; + other.cuLaunchConfig[3] = nullptr; + other.nvxLaunchInfo.pExtras = nullptr; + // fix-up internally-pointing pointers + cuLaunchConfig[1] = params.data(); + cuLaunchConfig[3] = ¶mSize; + nvxLaunchInfo.pExtras = cuLaunchConfig.data(); + } + + Com<CubinShaderWrapper> shader; + std::vector<uint8_t> params; + size_t paramSize; + VkCuLaunchInfoNVX nvxLaunchInfo = { VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX }; + std::array<void*, 5> cuLaunchConfig; + + std::vector<std::pair<Rc<DxvkBuffer>, DxvkAccessFlags>> buffers; + std::vector<std::pair<Rc<DxvkImage>, DxvkAccessFlags>> images; + + void insertResource(ID3D11Resource* pResource, DxvkAccessFlags access); + + template<typename T> + static void insertUniqueResource(std::vector<std::pair<T, DxvkAccessFlags>>& list, const T& resource, DxvkAccessFlags access); + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.cpp new file mode 100644 index 00000000..b095e5ea --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.cpp @@ -0,0 +1,166 @@ +#include "d3d11_depth_stencil.h" +#include "d3d11_device.h" + +namespace dxvk { + + D3D11DepthStencilState::D3D11DepthStencilState( + D3D11Device* device, + const D3D11_DEPTH_STENCIL_DESC& desc) + : D3D11StateObject<ID3D11DepthStencilState>(device), + m_desc(desc), m_d3d10(this) { + m_state.enableDepthTest = desc.DepthEnable; + m_state.enableDepthWrite = desc.DepthWriteMask == D3D11_DEPTH_WRITE_MASK_ALL; + m_state.enableStencilTest = desc.StencilEnable; + m_state.depthCompareOp = DecodeCompareOp(desc.DepthFunc); + m_state.stencilOpFront = DecodeStencilOpState(desc.FrontFace, desc); + m_state.stencilOpBack = DecodeStencilOpState(desc.BackFace, desc); + } + + + D3D11DepthStencilState::~D3D11DepthStencilState() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11DepthStencilState::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11DepthStencilState)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10DepthStencilState)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11DepthStencilState::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11DepthStencilState::GetDesc(D3D11_DEPTH_STENCIL_DESC* pDesc) { + *pDesc = m_desc; + } + + + void D3D11DepthStencilState::BindToContext(const Rc<DxvkContext>& ctx) { + ctx->setDepthStencilState(m_state); + } + + + HRESULT D3D11DepthStencilState::NormalizeDesc(D3D11_DEPTH_STENCIL_DESC* pDesc) { + if (pDesc->DepthEnable) { + pDesc->DepthEnable = TRUE; + + if (!ValidateDepthFunc(pDesc->DepthFunc)) + return E_INVALIDARG; + } else { + pDesc->DepthFunc = D3D11_COMPARISON_LESS; + pDesc->DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + } + + if (!ValidateDepthWriteMask(pDesc->DepthWriteMask)) + return E_INVALIDARG; + + if (pDesc->StencilEnable) { + pDesc->StencilEnable = TRUE; + + if (!ValidateStencilFunc(pDesc->FrontFace.StencilFunc) + || !ValidateStencilOp(pDesc->FrontFace.StencilFailOp) + || !ValidateStencilOp(pDesc->FrontFace.StencilDepthFailOp) + || !ValidateStencilOp(pDesc->FrontFace.StencilPassOp)) + return E_INVALIDARG; + + if (!ValidateStencilFunc(pDesc->BackFace.StencilFunc) + || !ValidateStencilOp(pDesc->BackFace.StencilFailOp) + || !ValidateStencilOp(pDesc->BackFace.StencilDepthFailOp) + || !ValidateStencilOp(pDesc->BackFace.StencilPassOp)) + return E_INVALIDARG; + } else { + D3D11_DEPTH_STENCILOP_DESC stencilOp; + stencilOp.StencilFailOp = D3D11_STENCIL_OP_KEEP; + stencilOp.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + stencilOp.StencilPassOp = D3D11_STENCIL_OP_KEEP; + stencilOp.StencilFunc = D3D11_COMPARISON_ALWAYS; + + pDesc->FrontFace = stencilOp; + pDesc->BackFace = stencilOp; + pDesc->StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + pDesc->StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + } + + return S_OK; + } + + + VkStencilOpState D3D11DepthStencilState::DecodeStencilOpState( + const D3D11_DEPTH_STENCILOP_DESC& StencilDesc, + const D3D11_DEPTH_STENCIL_DESC& Desc) const { + VkStencilOpState result; + result.failOp = VK_STENCIL_OP_KEEP; + result.passOp = VK_STENCIL_OP_KEEP; + result.depthFailOp = VK_STENCIL_OP_KEEP; + result.compareOp = VK_COMPARE_OP_ALWAYS; + result.compareMask = Desc.StencilReadMask; + result.writeMask = Desc.StencilWriteMask; + result.reference = 0; + + if (Desc.StencilEnable) { + result.failOp = DecodeStencilOp(StencilDesc.StencilFailOp); + result.passOp = DecodeStencilOp(StencilDesc.StencilPassOp); + result.depthFailOp = DecodeStencilOp(StencilDesc.StencilDepthFailOp); + result.compareOp = DecodeCompareOp(StencilDesc.StencilFunc); + } + + return result; + } + + + VkStencilOp D3D11DepthStencilState::DecodeStencilOp(D3D11_STENCIL_OP Op) const { + switch (Op) { + case D3D11_STENCIL_OP_KEEP: return VK_STENCIL_OP_KEEP; + case D3D11_STENCIL_OP_ZERO: return VK_STENCIL_OP_ZERO; + case D3D11_STENCIL_OP_REPLACE: return VK_STENCIL_OP_REPLACE; + case D3D11_STENCIL_OP_INCR_SAT: return VK_STENCIL_OP_INCREMENT_AND_CLAMP; + case D3D11_STENCIL_OP_DECR_SAT: return VK_STENCIL_OP_DECREMENT_AND_CLAMP; + case D3D11_STENCIL_OP_INVERT: return VK_STENCIL_OP_INVERT; + case D3D11_STENCIL_OP_INCR: return VK_STENCIL_OP_INCREMENT_AND_WRAP; + case D3D11_STENCIL_OP_DECR: return VK_STENCIL_OP_DECREMENT_AND_WRAP; + default: return VK_STENCIL_OP_KEEP; + } + } + + + bool D3D11DepthStencilState::ValidateDepthFunc(D3D11_COMPARISON_FUNC Comparison) { + return Comparison >= D3D11_COMPARISON_NEVER + && Comparison <= D3D11_COMPARISON_ALWAYS; + } + + + bool D3D11DepthStencilState::ValidateStencilFunc(D3D11_COMPARISON_FUNC Comparison) { + return Comparison >= D3D11_COMPARISON_NEVER + && Comparison <= D3D11_COMPARISON_ALWAYS; + } + + + bool D3D11DepthStencilState::ValidateStencilOp(D3D11_STENCIL_OP StencilOp) { + return StencilOp >= D3D11_STENCIL_OP_KEEP + && StencilOp <= D3D11_STENCIL_OP_DECR; + } + + + bool D3D11DepthStencilState::ValidateDepthWriteMask(D3D11_DEPTH_WRITE_MASK Mask) { + return Mask == D3D11_DEPTH_WRITE_MASK_ZERO + || Mask == D3D11_DEPTH_WRITE_MASK_ALL; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.h new file mode 100644 index 00000000..6311259f --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.h @@ -0,0 +1,68 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_depth_stencil.h" + +#include "d3d11_device_child.h" +#include "d3d11_util.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11DepthStencilState : public D3D11StateObject<ID3D11DepthStencilState> { + + public: + + using DescType = D3D11_DEPTH_STENCIL_DESC; + + D3D11DepthStencilState( + D3D11Device* device, + const D3D11_DEPTH_STENCIL_DESC& desc); + ~D3D11DepthStencilState(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void STDMETHODCALLTYPE GetDesc( + D3D11_DEPTH_STENCIL_DESC* pDesc) final; + + void BindToContext( + const Rc<DxvkContext>& ctx); + + D3D10DepthStencilState* GetD3D10Iface() { + return &m_d3d10; + } + + static HRESULT NormalizeDesc( + D3D11_DEPTH_STENCIL_DESC* pDesc); + + private: + + D3D11_DEPTH_STENCIL_DESC m_desc; + DxvkDepthStencilState m_state; + D3D10DepthStencilState m_d3d10; + + VkStencilOpState DecodeStencilOpState( + const D3D11_DEPTH_STENCILOP_DESC& StencilDesc, + const D3D11_DEPTH_STENCIL_DESC& Desc) const; + + VkStencilOp DecodeStencilOp( + D3D11_STENCIL_OP Op) const; + + static bool ValidateDepthFunc( + D3D11_COMPARISON_FUNC Comparison); + + static bool ValidateStencilFunc( + D3D11_COMPARISON_FUNC Comparison); + + static bool ValidateStencilOp( + D3D11_STENCIL_OP StencilOp); + + static bool ValidateDepthWriteMask( + D3D11_DEPTH_WRITE_MASK Mask); + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.cpp new file mode 100644 index 00000000..d55c36ba --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.cpp @@ -0,0 +1,3447 @@ +#include <algorithm> +#include <cstring> + +#include "../dxgi/dxgi_monitor.h" +#include "../dxgi/dxgi_swapchain.h" + +#include "../dxvk/dxvk_adapter.h" +#include "../dxvk/dxvk_instance.h" + +#include "d3d11_buffer.h" +#include "d3d11_class_linkage.h" +#include "d3d11_context_def.h" +#include "d3d11_context_imm.h" +#include "d3d11_device.h" +#include "d3d11_input_layout.h" +#include "d3d11_interop.h" +#include "d3d11_query.h" +#include "d3d11_resource.h" +#include "d3d11_sampler.h" +#include "d3d11_shader.h" +#include "d3d11_state_object.h" +#include "d3d11_swapchain.h" +#include "d3d11_texture.h" +#include "d3d11_video.h" + +namespace dxvk { + + constexpr uint32_t D3D11DXGIDevice::DefaultFrameLatency; + + + + D3D11Device::D3D11Device( + D3D11DXGIDevice* pContainer, + D3D_FEATURE_LEVEL FeatureLevel, + UINT FeatureFlags) + : m_container (pContainer), + m_featureLevel (FeatureLevel), + m_featureFlags (FeatureFlags), + m_dxvkDevice (pContainer->GetDXVKDevice()), + m_dxvkAdapter (m_dxvkDevice->adapter()), + m_d3d11Formats (m_dxvkAdapter), + m_d3d11Options (m_dxvkDevice->instance()->config(), m_dxvkDevice), + m_dxbcOptions (m_dxvkDevice, m_d3d11Options) { + m_initializer = new D3D11Initializer(this); + m_context = new D3D11ImmediateContext(this, m_dxvkDevice); + m_d3d10Device = new D3D10Device(this, m_context.ptr()); + } + + + D3D11Device::~D3D11Device() { + delete m_d3d10Device; + m_context = nullptr; + delete m_initializer; + } + + + ULONG STDMETHODCALLTYPE D3D11Device::AddRef() { + return m_container->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11Device::Release() { + return m_container->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::QueryInterface(REFIID riid, void** ppvObject) { + return m_container->QueryInterface(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateBuffer( + const D3D11_BUFFER_DESC* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Buffer** ppBuffer) { + InitReturnPtr(ppBuffer); + + if (!pDesc) + return E_INVALIDARG; + + D3D11_BUFFER_DESC desc = *pDesc; + HRESULT hr = D3D11Buffer::NormalizeBufferProperties(&desc); + + if (FAILED(hr)) + return hr; + + if (!ppBuffer) + return S_FALSE; + + try { + const Com<D3D11Buffer> buffer = new D3D11Buffer(this, &desc); + m_initializer->InitBuffer(buffer.ptr(), pInitialData); + *ppBuffer = buffer.ref(); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture1D( + const D3D11_TEXTURE1D_DESC* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture1D** ppTexture1D) { + InitReturnPtr(ppTexture1D); + + if (!pDesc) + return E_INVALIDARG; + + D3D11_COMMON_TEXTURE_DESC desc; + desc.Width = pDesc->Width; + desc.Height = 1; + desc.Depth = 1; + desc.MipLevels = pDesc->MipLevels; + desc.ArraySize = pDesc->ArraySize; + desc.Format = pDesc->Format; + desc.SampleDesc = DXGI_SAMPLE_DESC { 1, 0 }; + desc.Usage = pDesc->Usage; + desc.BindFlags = pDesc->BindFlags; + desc.CPUAccessFlags = pDesc->CPUAccessFlags; + desc.MiscFlags = pDesc->MiscFlags; + desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED; + + HRESULT hr = D3D11CommonTexture::NormalizeTextureProperties(&desc); + + if (FAILED(hr)) + return hr; + + if (!ppTexture1D) + return S_FALSE; + + try { + const Com<D3D11Texture1D> texture = new D3D11Texture1D(this, &desc); + m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData); + *ppTexture1D = texture.ref(); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture2D( + const D3D11_TEXTURE2D_DESC* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture2D** ppTexture2D) { + InitReturnPtr(ppTexture2D); + + if (!pDesc) + return E_INVALIDARG; + + D3D11_TEXTURE2D_DESC1 desc; + desc.Width = pDesc->Width; + desc.Height = pDesc->Height; + desc.MipLevels = pDesc->MipLevels; + desc.ArraySize = pDesc->ArraySize; + desc.Format = pDesc->Format; + desc.SampleDesc = pDesc->SampleDesc; + desc.Usage = pDesc->Usage; + desc.BindFlags = pDesc->BindFlags; + desc.CPUAccessFlags = pDesc->CPUAccessFlags; + desc.MiscFlags = pDesc->MiscFlags; + desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED; + + ID3D11Texture2D1* texture2D = nullptr; + HRESULT hr = CreateTexture2D1(&desc, pInitialData, ppTexture2D ? &texture2D : nullptr); + + if (hr != S_OK) + return hr; + + *ppTexture2D = texture2D; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture2D1( + const D3D11_TEXTURE2D_DESC1* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture2D1** ppTexture2D) { + InitReturnPtr(ppTexture2D); + + if (!pDesc) + return E_INVALIDARG; + + D3D11_COMMON_TEXTURE_DESC desc; + desc.Width = pDesc->Width; + desc.Height = pDesc->Height; + desc.Depth = 1; + desc.MipLevels = pDesc->MipLevels; + desc.ArraySize = pDesc->ArraySize; + desc.Format = pDesc->Format; + desc.SampleDesc = pDesc->SampleDesc; + desc.Usage = pDesc->Usage; + desc.BindFlags = pDesc->BindFlags; + desc.CPUAccessFlags = pDesc->CPUAccessFlags; + desc.MiscFlags = pDesc->MiscFlags; + desc.TextureLayout = pDesc->TextureLayout; + + HRESULT hr = D3D11CommonTexture::NormalizeTextureProperties(&desc); + + if (FAILED(hr)) + return hr; + + if (!ppTexture2D) + return S_FALSE; + + try { + Com<D3D11Texture2D> texture = new D3D11Texture2D(this, &desc); + m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData); + *ppTexture2D = texture.ref(); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture3D( + const D3D11_TEXTURE3D_DESC* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture3D** ppTexture3D) { + InitReturnPtr(ppTexture3D); + + if (!pDesc) + return E_INVALIDARG; + + D3D11_TEXTURE3D_DESC1 desc; + desc.Width = pDesc->Width; + desc.Height = pDesc->Height; + desc.Depth = pDesc->Depth; + desc.MipLevels = pDesc->MipLevels; + desc.Format = pDesc->Format; + desc.Usage = pDesc->Usage; + desc.BindFlags = pDesc->BindFlags; + desc.CPUAccessFlags = pDesc->CPUAccessFlags; + desc.MiscFlags = pDesc->MiscFlags; + desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED; + + ID3D11Texture3D1* texture3D = nullptr; + HRESULT hr = CreateTexture3D1(&desc, pInitialData, ppTexture3D ? &texture3D : nullptr); + + if (hr != S_OK) + return hr; + + *ppTexture3D = texture3D; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture3D1( + const D3D11_TEXTURE3D_DESC1* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture3D1** ppTexture3D) { + InitReturnPtr(ppTexture3D); + + if (!pDesc) + return E_INVALIDARG; + + D3D11_COMMON_TEXTURE_DESC desc; + desc.Width = pDesc->Width; + desc.Height = pDesc->Height; + desc.Depth = pDesc->Depth; + desc.MipLevels = pDesc->MipLevels; + desc.ArraySize = 1; + desc.Format = pDesc->Format; + desc.SampleDesc = DXGI_SAMPLE_DESC { 1, 0 }; + desc.Usage = pDesc->Usage; + desc.BindFlags = pDesc->BindFlags; + desc.CPUAccessFlags = pDesc->CPUAccessFlags; + desc.MiscFlags = pDesc->MiscFlags; + desc.TextureLayout = pDesc->TextureLayout; + + HRESULT hr = D3D11CommonTexture::NormalizeTextureProperties(&desc); + + if (FAILED(hr)) + return hr; + + if (!ppTexture3D) + return S_FALSE; + + try { + Com<D3D11Texture3D> texture = new D3D11Texture3D(this, &desc); + m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData); + *ppTexture3D = texture.ref(); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateShaderResourceView( + ID3D11Resource* pResource, + const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, + ID3D11ShaderResourceView** ppSRView) { + InitReturnPtr(ppSRView); + + uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN); + + D3D11_SHADER_RESOURCE_VIEW_DESC1 desc = pDesc + ? D3D11ShaderResourceView::PromoteDesc(pDesc, plane) + : D3D11_SHADER_RESOURCE_VIEW_DESC1(); + + ID3D11ShaderResourceView1* view = nullptr; + + HRESULT hr = CreateShaderResourceView1(pResource, + pDesc ? &desc : nullptr, + ppSRView ? &view : nullptr); + + if (hr != S_OK) + return hr; + + *ppSRView = view; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateShaderResourceView1( + ID3D11Resource* pResource, + const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc, + ID3D11ShaderResourceView1** ppSRView) { + InitReturnPtr(ppSRView); + + if (!pResource) + return E_INVALIDARG; + + D3D11_COMMON_RESOURCE_DESC resourceDesc; + GetCommonResourceDesc(pResource, &resourceDesc); + + // The description is optional. If omitted, we'll create + // a view that covers all subresources of the image. + D3D11_SHADER_RESOURCE_VIEW_DESC1 desc; + + if (!pDesc) { + if (FAILED(D3D11ShaderResourceView::GetDescFromResource(pResource, &desc))) + return E_INVALIDARG; + } else { + desc = *pDesc; + + if (FAILED(D3D11ShaderResourceView::NormalizeDesc(pResource, &desc))) + return E_INVALIDARG; + } + + uint32_t plane = D3D11ShaderResourceView::GetPlaneSlice(&desc); + + if (!CheckResourceViewCompatibility(pResource, D3D11_BIND_SHADER_RESOURCE, desc.Format, plane)) { + Logger::err(str::format("D3D11: Cannot create shader resource view:", + "\n Resource type: ", resourceDesc.Dim, + "\n Resource usage: ", resourceDesc.BindFlags, + "\n Resource format: ", resourceDesc.Format, + "\n View format: ", desc.Format, + "\n View plane: ", plane)); + return E_INVALIDARG; + } + + if (!ppSRView) + return S_FALSE; + + try { + *ppSRView = ref(new D3D11ShaderResourceView(this, pResource, &desc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateUnorderedAccessView( + ID3D11Resource* pResource, + const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, + ID3D11UnorderedAccessView** ppUAView) { + InitReturnPtr(ppUAView); + + uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN); + + D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc = pDesc + ? D3D11UnorderedAccessView::PromoteDesc(pDesc, plane) + : D3D11_UNORDERED_ACCESS_VIEW_DESC1(); + + ID3D11UnorderedAccessView1* view = nullptr; + + HRESULT hr = CreateUnorderedAccessView1(pResource, + pDesc ? &desc : nullptr, + ppUAView ? &view : nullptr); + + if (hr != S_OK) + return hr; + + *ppUAView = view; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateUnorderedAccessView1( + ID3D11Resource* pResource, + const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc, + ID3D11UnorderedAccessView1** ppUAView) { + InitReturnPtr(ppUAView); + + if (!pResource) + return E_INVALIDARG; + + D3D11_COMMON_RESOURCE_DESC resourceDesc; + GetCommonResourceDesc(pResource, &resourceDesc); + + // The description is optional. If omitted, we'll create + // a view that covers all subresources of the image. + D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc; + + if (!pDesc) { + if (FAILED(D3D11UnorderedAccessView::GetDescFromResource(pResource, &desc))) + return E_INVALIDARG; + } else { + desc = *pDesc; + + if (FAILED(D3D11UnorderedAccessView::NormalizeDesc(pResource, &desc))) + return E_INVALIDARG; + } + + uint32_t plane = D3D11UnorderedAccessView::GetPlaneSlice(&desc); + + if (!CheckResourceViewCompatibility(pResource, D3D11_BIND_UNORDERED_ACCESS, desc.Format, plane)) { + Logger::err(str::format("D3D11: Cannot create unordered access view:", + "\n Resource type: ", resourceDesc.Dim, + "\n Resource usage: ", resourceDesc.BindFlags, + "\n Resource format: ", resourceDesc.Format, + "\n View format: ", desc.Format, + "\n View plane: ", plane)); + return E_INVALIDARG; + } + + if (!ppUAView) + return S_FALSE; + + try { + auto uav = new D3D11UnorderedAccessView(this, pResource, &desc); + m_initializer->InitUavCounter(uav); + *ppUAView = ref(uav); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateRenderTargetView( + ID3D11Resource* pResource, + const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, + ID3D11RenderTargetView** ppRTView) { + InitReturnPtr(ppRTView); + + uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN); + + D3D11_RENDER_TARGET_VIEW_DESC1 desc = pDesc + ? D3D11RenderTargetView::PromoteDesc(pDesc, plane) + : D3D11_RENDER_TARGET_VIEW_DESC1(); + + ID3D11RenderTargetView1* view = nullptr; + + HRESULT hr = CreateRenderTargetView1(pResource, + pDesc ? &desc : nullptr, + ppRTView ? &view : nullptr); + + if (hr != S_OK) + return hr; + + *ppRTView = view; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateRenderTargetView1( + ID3D11Resource* pResource, + const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc, + ID3D11RenderTargetView1** ppRTView) { + InitReturnPtr(ppRTView); + + if (!pResource) + return E_INVALIDARG; + + // DXVK only supports render target views for image resources + D3D11_COMMON_RESOURCE_DESC resourceDesc; + GetCommonResourceDesc(pResource, &resourceDesc); + + if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) { + Logger::warn("D3D11: Cannot create render target view for a buffer"); + return S_OK; // It is required to run Battlefield 3 and Battlefield 4. + } + + // The view description is optional. If not defined, it + // will use the resource's format and all array layers. + D3D11_RENDER_TARGET_VIEW_DESC1 desc; + + if (!pDesc) { + if (FAILED(D3D11RenderTargetView::GetDescFromResource(pResource, &desc))) + return E_INVALIDARG; + } else { + desc = *pDesc; + + if (FAILED(D3D11RenderTargetView::NormalizeDesc(pResource, &desc))) + return E_INVALIDARG; + } + + uint32_t plane = D3D11RenderTargetView::GetPlaneSlice(&desc); + + if (!CheckResourceViewCompatibility(pResource, D3D11_BIND_RENDER_TARGET, desc.Format, plane)) { + Logger::err(str::format("D3D11: Cannot create render target view:", + "\n Resource type: ", resourceDesc.Dim, + "\n Resource usage: ", resourceDesc.BindFlags, + "\n Resource format: ", resourceDesc.Format, + "\n View format: ", desc.Format, + "\n View plane: ", plane)); + return E_INVALIDARG; + } + + if (!ppRTView) + return S_FALSE; + + try { + *ppRTView = ref(new D3D11RenderTargetView(this, pResource, &desc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateDepthStencilView( + ID3D11Resource* pResource, + const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, + ID3D11DepthStencilView** ppDepthStencilView) { + InitReturnPtr(ppDepthStencilView); + + if (pResource == nullptr) + return E_INVALIDARG; + + D3D11_COMMON_RESOURCE_DESC resourceDesc; + GetCommonResourceDesc(pResource, &resourceDesc); + + // The view description is optional. If not defined, it + // will use the resource's format and all array layers. + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + + if (pDesc == nullptr) { + if (FAILED(D3D11DepthStencilView::GetDescFromResource(pResource, &desc))) + return E_INVALIDARG; + } else { + desc = *pDesc; + + if (FAILED(D3D11DepthStencilView::NormalizeDesc(pResource, &desc))) + return E_INVALIDARG; + } + + if (!CheckResourceViewCompatibility(pResource, D3D11_BIND_DEPTH_STENCIL, desc.Format, 0)) { + Logger::err(str::format("D3D11: Cannot create depth-stencil view:", + "\n Resource type: ", resourceDesc.Dim, + "\n Resource usage: ", resourceDesc.BindFlags, + "\n Resource format: ", resourceDesc.Format, + "\n View format: ", desc.Format)); + return E_INVALIDARG; + } + + if (ppDepthStencilView == nullptr) + return S_FALSE; + + try { + *ppDepthStencilView = ref(new D3D11DepthStencilView(this, pResource, &desc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateInputLayout( + const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, + UINT NumElements, + const void* pShaderBytecodeWithInputSignature, + SIZE_T BytecodeLength, + ID3D11InputLayout** ppInputLayout) { + InitReturnPtr(ppInputLayout); + + if (pInputElementDescs == nullptr) + return E_INVALIDARG; + + try { + DxbcReader dxbcReader(reinterpret_cast<const char*>( + pShaderBytecodeWithInputSignature), BytecodeLength); + DxbcModule dxbcModule(dxbcReader); + + const Rc<DxbcIsgn> inputSignature = dxbcModule.isgn(); + + uint32_t attrMask = 0; + uint32_t bindMask = 0; + + std::array<DxvkVertexAttribute, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> attrList; + std::array<DxvkVertexBinding, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> bindList; + + for (uint32_t i = 0; i < NumElements; i++) { + const DxbcSgnEntry* entry = inputSignature->find( + pInputElementDescs[i].SemanticName, + pInputElementDescs[i].SemanticIndex, 0); + + if (entry == nullptr) { + Logger::debug(str::format( + "D3D11Device: No such vertex shader semantic: ", + pInputElementDescs[i].SemanticName, + pInputElementDescs[i].SemanticIndex)); + } + + // Create vertex input attribute description + DxvkVertexAttribute attrib; + attrib.location = entry != nullptr ? entry->registerId : 0; + attrib.binding = pInputElementDescs[i].InputSlot; + attrib.format = LookupFormat(pInputElementDescs[i].Format, DXGI_VK_FORMAT_MODE_COLOR).Format; + attrib.offset = pInputElementDescs[i].AlignedByteOffset; + + // The application may choose to let the implementation + // generate the exact vertex layout. In that case we'll + // pack attributes on the same binding in the order they + // are declared, aligning each attribute to four bytes. + const DxvkFormatInfo* formatInfo = imageFormatInfo(attrib.format); + VkDeviceSize alignment = std::min<VkDeviceSize>(formatInfo->elementSize, 4); + + if (attrib.offset == D3D11_APPEND_ALIGNED_ELEMENT) { + attrib.offset = 0; + + for (uint32_t j = 1; j <= i; j++) { + const DxvkVertexAttribute& prev = attrList.at(i - j); + + if (prev.binding == attrib.binding) { + attrib.offset = align(prev.offset + imageFormatInfo(prev.format)->elementSize, alignment); + break; + } + } + } else if (attrib.offset & (alignment - 1)) + return E_INVALIDARG; + + attrList.at(i) = attrib; + + // Create vertex input binding description. The + // stride is dynamic state in D3D11 and will be + // set by D3D11DeviceContext::IASetVertexBuffers. + DxvkVertexBinding binding; + binding.binding = pInputElementDescs[i].InputSlot; + binding.fetchRate = pInputElementDescs[i].InstanceDataStepRate; + binding.inputRate = pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA + ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; + + // Check if the binding was already defined. If so, the + // parameters must be identical (namely, the input rate). + bool bindingDefined = false; + + for (uint32_t j = 0; j < i; j++) { + uint32_t bindingId = attrList.at(j).binding; + + if (binding.binding == bindingId) { + bindingDefined = true; + + if (binding.inputRate != bindList.at(bindingId).inputRate) { + Logger::err(str::format( + "D3D11Device: Conflicting input rate for binding ", + binding.binding)); + return E_INVALIDARG; + } + } + } + + if (!bindingDefined) + bindList.at(binding.binding) = binding; + + if (entry != nullptr) { + attrMask |= 1u << i; + bindMask |= 1u << binding.binding; + } + } + + // Compact the attribute and binding lists to filter + // out attributes and bindings not used by the shader + uint32_t attrCount = CompactSparseList(attrList.data(), attrMask); + uint32_t bindCount = CompactSparseList(bindList.data(), bindMask); + + // Check if there are any semantics defined in the + // shader that are not included in the current input + // layout. + for (auto i = inputSignature->begin(); i != inputSignature->end(); i++) { + bool found = i->systemValue != DxbcSystemValue::None; + + for (uint32_t j = 0; j < attrCount && !found; j++) + found = attrList.at(j).location == i->registerId; + + if (!found) { + Logger::warn(str::format( + "D3D11Device: Vertex input '", + i->semanticName, i->semanticIndex, + "' not defined by input layout")); + } + } + + // Create the actual input layout object + // if the application requests it. + if (ppInputLayout != nullptr) { + *ppInputLayout = ref( + new D3D11InputLayout(this, + attrCount, attrList.data(), + bindCount, bindList.data())); + } + + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateVertexShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11VertexShader** ppVertexShader) { + InitReturnPtr(ppVertexShader); + D3D11CommonShader module; + + DxbcModuleInfo moduleInfo; + moduleInfo.options = m_dxbcOptions; + moduleInfo.tess = nullptr; + moduleInfo.xfb = nullptr; + + Sha1Hash hash = Sha1Hash::compute( + pShaderBytecode, BytecodeLength); + + HRESULT hr = CreateShaderModule(&module, + DxvkShaderKey(VK_SHADER_STAGE_VERTEX_BIT, hash), + pShaderBytecode, BytecodeLength, pClassLinkage, + &moduleInfo); + + if (FAILED(hr)) + return hr; + + if (!ppVertexShader) + return S_FALSE; + + *ppVertexShader = ref(new D3D11VertexShader(this, module)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateGeometryShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11GeometryShader** ppGeometryShader) { + InitReturnPtr(ppGeometryShader); + D3D11CommonShader module; + + DxbcModuleInfo moduleInfo; + moduleInfo.options = m_dxbcOptions; + moduleInfo.tess = nullptr; + moduleInfo.xfb = nullptr; + + Sha1Hash hash = Sha1Hash::compute( + pShaderBytecode, BytecodeLength); + + HRESULT hr = CreateShaderModule(&module, + DxvkShaderKey(VK_SHADER_STAGE_GEOMETRY_BIT, hash), + pShaderBytecode, BytecodeLength, pClassLinkage, + &moduleInfo); + + if (FAILED(hr)) + return hr; + + if (!ppGeometryShader) + return S_FALSE; + + *ppGeometryShader = ref(new D3D11GeometryShader(this, module)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateGeometryShaderWithStreamOutput( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + const D3D11_SO_DECLARATION_ENTRY* pSODeclaration, + UINT NumEntries, + const UINT* pBufferStrides, + UINT NumStrides, + UINT RasterizedStream, + ID3D11ClassLinkage* pClassLinkage, + ID3D11GeometryShader** ppGeometryShader) { + InitReturnPtr(ppGeometryShader); + D3D11CommonShader module; + + if (!m_dxvkDevice->features().extTransformFeedback.transformFeedback) + return DXGI_ERROR_INVALID_CALL; + + // Zero-init some counterss so that we can increment + // them while walking over the stream output entries + DxbcXfbInfo xfb = { }; + + for (uint32_t i = 0; i < NumEntries; i++) { + const D3D11_SO_DECLARATION_ENTRY* so = &pSODeclaration[i]; + + if (so->OutputSlot >= D3D11_SO_BUFFER_SLOT_COUNT) + return E_INVALIDARG; + + if (so->SemanticName != nullptr) { + if (so->Stream >= D3D11_SO_BUFFER_SLOT_COUNT + || so->StartComponent >= 4 + || so->ComponentCount < 1 + || so->ComponentCount > 4) + return E_INVALIDARG; + + DxbcXfbEntry* entry = &xfb.entries[xfb.entryCount++]; + entry->semanticName = so->SemanticName; + entry->semanticIndex = so->SemanticIndex; + entry->componentIndex = so->StartComponent; + entry->componentCount = so->ComponentCount; + entry->streamId = so->Stream; + entry->bufferId = so->OutputSlot; + entry->offset = xfb.strides[so->OutputSlot]; + } + + xfb.strides[so->OutputSlot] += so->ComponentCount * sizeof(uint32_t); + } + + // If necessary, override the buffer strides + for (uint32_t i = 0; i < NumStrides; i++) + xfb.strides[i] = pBufferStrides[i]; + + // Set stream to rasterize, if any + xfb.rasterizedStream = -1; + + if (RasterizedStream != D3D11_SO_NO_RASTERIZED_STREAM) + Logger::err("D3D11: CreateGeometryShaderWithStreamOutput: Rasterized stream not supported"); + + // Compute hash from both the xfb info and the source + // code, because both influence the generated code + DxbcXfbInfo hashXfb = xfb; + + std::vector<Sha1Data> chunks = {{ + { pShaderBytecode, BytecodeLength }, + { &hashXfb, sizeof(hashXfb) }, + }}; + + for (uint32_t i = 0; i < hashXfb.entryCount; i++) { + const char* semantic = hashXfb.entries[i].semanticName; + + if (semantic) { + chunks.push_back({ semantic, std::strlen(semantic) }); + hashXfb.entries[i].semanticName = nullptr; + } + } + + Sha1Hash hash = Sha1Hash::compute(chunks.size(), chunks.data()); + + // Create the actual shader module + DxbcModuleInfo moduleInfo; + moduleInfo.options = m_dxbcOptions; + moduleInfo.tess = nullptr; + moduleInfo.xfb = &xfb; + + HRESULT hr = CreateShaderModule(&module, + DxvkShaderKey(VK_SHADER_STAGE_GEOMETRY_BIT, hash), + pShaderBytecode, BytecodeLength, pClassLinkage, + &moduleInfo); + + if (FAILED(hr)) + return E_INVALIDARG; + + if (!ppGeometryShader) + return S_FALSE; + + *ppGeometryShader = ref(new D3D11GeometryShader(this, module)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreatePixelShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11PixelShader** ppPixelShader) { + InitReturnPtr(ppPixelShader); + D3D11CommonShader module; + + DxbcModuleInfo moduleInfo; + moduleInfo.options = m_dxbcOptions; + moduleInfo.tess = nullptr; + moduleInfo.xfb = nullptr; + + Sha1Hash hash = Sha1Hash::compute( + pShaderBytecode, BytecodeLength); + + + HRESULT hr = CreateShaderModule(&module, + DxvkShaderKey(VK_SHADER_STAGE_FRAGMENT_BIT, hash), + pShaderBytecode, BytecodeLength, pClassLinkage, + &moduleInfo); + + if (FAILED(hr)) + return hr; + + if (!ppPixelShader) + return S_FALSE; + + *ppPixelShader = ref(new D3D11PixelShader(this, module)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateHullShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11HullShader** ppHullShader) { + InitReturnPtr(ppHullShader); + D3D11CommonShader module; + + DxbcTessInfo tessInfo; + tessInfo.maxTessFactor = float(m_d3d11Options.maxTessFactor); + + DxbcModuleInfo moduleInfo; + moduleInfo.options = m_dxbcOptions; + moduleInfo.tess = nullptr; + moduleInfo.xfb = nullptr; + + if (tessInfo.maxTessFactor >= 8.0f) + moduleInfo.tess = &tessInfo; + + Sha1Hash hash = Sha1Hash::compute( + pShaderBytecode, BytecodeLength); + + HRESULT hr = CreateShaderModule(&module, + DxvkShaderKey(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, hash), + pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); + + if (FAILED(hr)) + return hr; + + if (!ppHullShader) + return S_FALSE; + + *ppHullShader = ref(new D3D11HullShader(this, module)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateDomainShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11DomainShader** ppDomainShader) { + InitReturnPtr(ppDomainShader); + D3D11CommonShader module; + + DxbcModuleInfo moduleInfo; + moduleInfo.options = m_dxbcOptions; + moduleInfo.tess = nullptr; + moduleInfo.xfb = nullptr; + + Sha1Hash hash = Sha1Hash::compute( + pShaderBytecode, BytecodeLength); + + HRESULT hr = CreateShaderModule(&module, + DxvkShaderKey(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, hash), + pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); + + if (FAILED(hr)) + return hr; + + if (ppDomainShader == nullptr) + return S_FALSE; + + *ppDomainShader = ref(new D3D11DomainShader(this, module)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateComputeShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11ComputeShader** ppComputeShader) { + InitReturnPtr(ppComputeShader); + D3D11CommonShader module; + + DxbcModuleInfo moduleInfo; + moduleInfo.options = m_dxbcOptions; + moduleInfo.tess = nullptr; + moduleInfo.xfb = nullptr; + + Sha1Hash hash = Sha1Hash::compute( + pShaderBytecode, BytecodeLength); + + HRESULT hr = CreateShaderModule(&module, + DxvkShaderKey(VK_SHADER_STAGE_COMPUTE_BIT, hash), + pShaderBytecode, BytecodeLength, pClassLinkage, + &moduleInfo); + + if (FAILED(hr)) + return hr; + + if (!ppComputeShader) + return S_FALSE; + + *ppComputeShader = ref(new D3D11ComputeShader(this, module)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateClassLinkage(ID3D11ClassLinkage** ppLinkage) { + *ppLinkage = ref(new D3D11ClassLinkage(this)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateBlendState( + const D3D11_BLEND_DESC* pBlendStateDesc, + ID3D11BlendState** ppBlendState) { + InitReturnPtr(ppBlendState); + + if (!pBlendStateDesc) + return E_INVALIDARG; + + D3D11_BLEND_DESC1 desc = D3D11BlendState::PromoteDesc(pBlendStateDesc); + + if (FAILED(D3D11BlendState::NormalizeDesc(&desc))) + return E_INVALIDARG; + + if (ppBlendState != nullptr) { + *ppBlendState = m_bsStateObjects.Create(this, desc); + return S_OK; + } return S_FALSE; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateBlendState1( + const D3D11_BLEND_DESC1* pBlendStateDesc, + ID3D11BlendState1** ppBlendState) { + InitReturnPtr(ppBlendState); + + if (!pBlendStateDesc) + return E_INVALIDARG; + + D3D11_BLEND_DESC1 desc = *pBlendStateDesc; + + if (FAILED(D3D11BlendState::NormalizeDesc(&desc))) + return E_INVALIDARG; + + if (ppBlendState != nullptr) { + *ppBlendState = m_bsStateObjects.Create(this, desc); + return S_OK; + } return S_FALSE; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateDepthStencilState( + const D3D11_DEPTH_STENCIL_DESC* pDepthStencilDesc, + ID3D11DepthStencilState** ppDepthStencilState) { + InitReturnPtr(ppDepthStencilState); + + if (!pDepthStencilDesc) + return E_INVALIDARG; + + D3D11_DEPTH_STENCIL_DESC desc = *pDepthStencilDesc; + + if (FAILED(D3D11DepthStencilState::NormalizeDesc(&desc))) + return E_INVALIDARG; + + if (ppDepthStencilState != nullptr) { + *ppDepthStencilState = m_dsStateObjects.Create(this, desc); + return S_OK; + } return S_FALSE; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateRasterizerState( + const D3D11_RASTERIZER_DESC* pRasterizerDesc, + ID3D11RasterizerState** ppRasterizerState) { + InitReturnPtr(ppRasterizerState); + + if (!pRasterizerDesc) + return E_INVALIDARG; + + D3D11_RASTERIZER_DESC2 desc = D3D11RasterizerState::PromoteDesc(pRasterizerDesc); + + if (FAILED(D3D11RasterizerState::NormalizeDesc(&desc))) + return E_INVALIDARG; + + if (!ppRasterizerState) + return S_FALSE; + + *ppRasterizerState = m_rsStateObjects.Create(this, desc); + return S_OK; + } + + + HRESULT D3D11Device::CreateRasterizerState1( + const D3D11_RASTERIZER_DESC1* pRasterizerDesc, + ID3D11RasterizerState1** ppRasterizerState) { + InitReturnPtr(ppRasterizerState); + + if (!pRasterizerDesc) + return E_INVALIDARG; + + D3D11_RASTERIZER_DESC2 desc = D3D11RasterizerState::PromoteDesc(pRasterizerDesc); + + if (FAILED(D3D11RasterizerState::NormalizeDesc(&desc))) + return E_INVALIDARG; + + if (!ppRasterizerState) + return S_FALSE; + + *ppRasterizerState = m_rsStateObjects.Create(this, desc); + return S_OK; + } + + + HRESULT D3D11Device::CreateRasterizerState2( + const D3D11_RASTERIZER_DESC2* pRasterizerDesc, + ID3D11RasterizerState2** ppRasterizerState) { + InitReturnPtr(ppRasterizerState); + + if (!pRasterizerDesc) + return E_INVALIDARG; + + D3D11_RASTERIZER_DESC2 desc = *pRasterizerDesc; + + if (FAILED(D3D11RasterizerState::NormalizeDesc(&desc))) + return E_INVALIDARG; + + if (desc.ConservativeRaster != D3D11_CONSERVATIVE_RASTERIZATION_MODE_OFF + && !m_dxvkDevice->extensions().extConservativeRasterization) + return E_INVALIDARG; + + if (!ppRasterizerState) + return S_FALSE; + + *ppRasterizerState = m_rsStateObjects.Create(this, desc); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateSamplerState( + const D3D11_SAMPLER_DESC* pSamplerDesc, + ID3D11SamplerState** ppSamplerState) { + InitReturnPtr(ppSamplerState); + + if (pSamplerDesc == nullptr) + return E_INVALIDARG; + + D3D11_SAMPLER_DESC desc = *pSamplerDesc; + + if (FAILED(D3D11SamplerState::NormalizeDesc(&desc))) + return E_INVALIDARG; + + if (ppSamplerState == nullptr) + return S_FALSE; + + try { + *ppSamplerState = m_samplerObjects.Create(this, desc); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateQuery( + const D3D11_QUERY_DESC* pQueryDesc, + ID3D11Query** ppQuery) { + InitReturnPtr(ppQuery); + + if (!pQueryDesc) + return E_INVALIDARG; + + D3D11_QUERY_DESC1 desc; + desc.Query = pQueryDesc->Query; + desc.MiscFlags = pQueryDesc->MiscFlags; + desc.ContextType = D3D11_CONTEXT_TYPE_ALL; + + ID3D11Query1* query = nullptr; + HRESULT hr = CreateQuery1(&desc, ppQuery ? &query : nullptr); + + if (hr != S_OK) + return hr; + + *ppQuery = query; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateQuery1( + const D3D11_QUERY_DESC1* pQueryDesc, + ID3D11Query1** ppQuery) { + InitReturnPtr(ppQuery); + + if (!pQueryDesc) + return E_INVALIDARG; + + HRESULT hr = D3D11Query::ValidateDesc(pQueryDesc); + + if (FAILED(hr)) + return hr; + + if (!ppQuery) + return S_FALSE; + + try { + *ppQuery = ref(new D3D11Query(this, *pQueryDesc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreatePredicate( + const D3D11_QUERY_DESC* pPredicateDesc, + ID3D11Predicate** ppPredicate) { + InitReturnPtr(ppPredicate); + + if (!pPredicateDesc) + return E_INVALIDARG; + + D3D11_QUERY_DESC1 desc; + desc.Query = pPredicateDesc->Query; + desc.MiscFlags = pPredicateDesc->MiscFlags; + desc.ContextType = D3D11_CONTEXT_TYPE_ALL; + + if (desc.Query != D3D11_QUERY_OCCLUSION_PREDICATE) { + Logger::warn(str::format("D3D11: Unhandled predicate type: ", pPredicateDesc->Query)); + return E_INVALIDARG; + } + + if (!ppPredicate) + return S_FALSE; + + try { + *ppPredicate = D3D11Query::AsPredicate( + ref(new D3D11Query(this, desc))); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateCounter( + const D3D11_COUNTER_DESC* pCounterDesc, + ID3D11Counter** ppCounter) { + InitReturnPtr(ppCounter); + + Logger::err(str::format("D3D11: Unsupported counter: ", pCounterDesc->Counter)); + return E_INVALIDARG; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeferredContext( + UINT ContextFlags, + ID3D11DeviceContext** ppDeferredContext) { + *ppDeferredContext = ref(new D3D11DeferredContext(this, m_dxvkDevice, ContextFlags)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeferredContext1( + UINT ContextFlags, + ID3D11DeviceContext1** ppDeferredContext) { + *ppDeferredContext = ref(new D3D11DeferredContext(this, m_dxvkDevice, ContextFlags)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeferredContext2( + UINT ContextFlags, + ID3D11DeviceContext2** ppDeferredContext) { + *ppDeferredContext = ref(new D3D11DeferredContext(this, m_dxvkDevice, ContextFlags)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeferredContext3( + UINT ContextFlags, + ID3D11DeviceContext3** ppDeferredContext) { + *ppDeferredContext = ref(new D3D11DeferredContext(this, m_dxvkDevice, ContextFlags)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeviceContextState( + UINT Flags, + const D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + REFIID EmulatedInterface, + D3D_FEATURE_LEVEL* pChosenFeatureLevel, + ID3DDeviceContextState** ppContextState) { + InitReturnPtr(ppContextState); + + if (!pFeatureLevels || FeatureLevels == 0) + return E_INVALIDARG; + + if (EmulatedInterface != __uuidof(ID3D10Device) + && EmulatedInterface != __uuidof(ID3D10Device1) + && EmulatedInterface != __uuidof(ID3D11Device) + && EmulatedInterface != __uuidof(ID3D11Device1)) + return E_INVALIDARG; + + UINT flId; + for (flId = 0; flId < FeatureLevels; flId++) { + if (CheckFeatureLevelSupport(m_dxvkDevice->instance(), m_dxvkAdapter, pFeatureLevels[flId])) + break; + } + + if (flId == FeatureLevels) + return E_INVALIDARG; + + if (pFeatureLevels[flId] > m_featureLevel) + m_featureLevel = pFeatureLevels[flId]; + + if (pChosenFeatureLevel) + *pChosenFeatureLevel = pFeatureLevels[flId]; + + if (!ppContextState) + return S_FALSE; + + *ppContextState = ref(new D3D11DeviceContextState(this)); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CreateFence( + UINT64 InitialValue, + D3D11_FENCE_FLAG Flags, + REFIID ReturnedInterface, + void** ppFence) { + InitReturnPtr(ppFence); + + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11Device::CreateFence: Not implemented"); + + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11Device::ReadFromSubresource( + void* pDstData, + UINT DstRowPitch, + UINT DstDepthPitch, + ID3D11Resource* pSrcResource, + UINT SrcSubresource, + const D3D11_BOX* pSrcBox) { + CopySubresourceData( + pDstData, DstRowPitch, DstDepthPitch, + pSrcResource, SrcSubresource, pSrcBox); + } + + + void STDMETHODCALLTYPE D3D11Device::WriteToSubresource( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch) { + CopySubresourceData( + pSrcData, SrcRowPitch, SrcRowPitch, + pDstResource, DstSubresource, pDstBox); + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::OpenSharedResource( + HANDLE hResource, + REFIID ReturnedInterface, + void** ppResource) { + InitReturnPtr(ppResource); + + Logger::err("D3D11Device::OpenSharedResource: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::OpenSharedResource1( + HANDLE hResource, + REFIID ReturnedInterface, + void** ppResource) { + InitReturnPtr(ppResource); + + Logger::err("D3D11Device::OpenSharedResource1: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::OpenSharedResourceByName( + LPCWSTR lpName, + DWORD dwDesiredAccess, + REFIID returnedInterface, + void** ppResource) { + InitReturnPtr(ppResource); + + Logger::err("D3D11Device::OpenSharedResourceByName: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::OpenSharedFence( + HANDLE hFence, + REFIID ReturnedInterface, + void** ppFence) { + InitReturnPtr(ppFence); + + Logger::err("D3D11Device::OpenSharedFence: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CheckFormatSupport( + DXGI_FORMAT Format, + UINT* pFormatSupport) { + return GetFormatSupportFlags(Format, pFormatSupport, nullptr); + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CheckMultisampleQualityLevels( + DXGI_FORMAT Format, + UINT SampleCount, + UINT* pNumQualityLevels) { + return CheckMultisampleQualityLevels1(Format, SampleCount, 0, pNumQualityLevels); + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CheckMultisampleQualityLevels1( + DXGI_FORMAT Format, + UINT SampleCount, + UINT Flags, + UINT* pNumQualityLevels) { + // There are many error conditions, so we'll just assume + // that we will fail and return a non-zero value in case + // the device does actually support the format. + if (!pNumQualityLevels) + return E_INVALIDARG; + + // We don't support tiled resources, but it's unclear what + // we are supposed to return in this case. Be conservative. + if (Flags) { + *pNumQualityLevels = 0; + return E_FAIL; + } + + // For some reason, we can query DXGI_FORMAT_UNKNOWN + if (Format == DXGI_FORMAT_UNKNOWN) { + *pNumQualityLevels = SampleCount == 1 ? 1 : 0; + return SampleCount ? S_OK : E_FAIL; + } + + // All other unknown formats should result in an error return. + VkFormat format = LookupFormat(Format, DXGI_VK_FORMAT_MODE_ANY).Format; + + if (format == VK_FORMAT_UNDEFINED) + return E_INVALIDARG; + + // Zero-init now, leave value undefined otherwise. + // This does actually match native D3D11 behaviour. + *pNumQualityLevels = 0; + + // Non-power of two sample counts are not supported, but querying + // support for them is legal, so we return zero quality levels. + VkSampleCountFlagBits sampleCountFlag = VK_SAMPLE_COUNT_1_BIT; + + if (FAILED(DecodeSampleCount(SampleCount, &sampleCountFlag))) + return SampleCount && SampleCount <= 32 ? S_OK : E_FAIL; + + // Check if the device supports the given combination of format + // and sample count. D3D exposes the opaque concept of quality + // levels to the application, we'll just define one such level. + VkImageFormatProperties formatProps; + + VkResult status = m_dxvkAdapter->imageFormatProperties( + format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_SAMPLED_BIT, 0, formatProps); + + if ((status == VK_SUCCESS) && (formatProps.sampleCounts & sampleCountFlag)) + *pNumQualityLevels = 1; + return S_OK; + } + + + void STDMETHODCALLTYPE D3D11Device::CheckCounterInfo(D3D11_COUNTER_INFO* pCounterInfo) { + // We basically don't support counters + pCounterInfo->LastDeviceDependentCounter = D3D11_COUNTER(0); + pCounterInfo->NumSimultaneousCounters = 0; + pCounterInfo->NumDetectableParallelUnits = 0; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CheckCounter( + const D3D11_COUNTER_DESC* pDesc, + D3D11_COUNTER_TYPE* pType, + UINT* pActiveCounters, + LPSTR szName, + UINT* pNameLength, + LPSTR szUnits, + UINT* pUnitsLength, + LPSTR szDescription, + UINT* pDescriptionLength) { + Logger::err("D3D11: Counters not supported"); + return E_INVALIDARG; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::CheckFeatureSupport( + D3D11_FEATURE Feature, + void* pFeatureSupportData, + UINT FeatureSupportDataSize) { + switch (Feature) { + case D3D11_FEATURE_THREADING: { + auto info = static_cast<D3D11_FEATURE_DATA_THREADING*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + // We report native support for command lists here so that we do not actually + // have to re-implement the UpdateSubresource bug from the D3D11 runtime, see + // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx) + info->DriverConcurrentCreates = TRUE; + info->DriverCommandLists = TRUE; + } return S_OK; + + case D3D11_FEATURE_DOUBLES: { + auto info = static_cast<D3D11_FEATURE_DATA_DOUBLES*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->DoublePrecisionFloatShaderOps = m_dxvkDevice->features().core.features.shaderFloat64 + && m_dxvkDevice->features().core.features.shaderInt64; + } return S_OK; + + case D3D11_FEATURE_FORMAT_SUPPORT: { + auto info = static_cast<D3D11_FEATURE_DATA_FORMAT_SUPPORT*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + return GetFormatSupportFlags(info->InFormat, &info->OutFormatSupport, nullptr); + } return S_OK; + + case D3D11_FEATURE_FORMAT_SUPPORT2: { + auto info = static_cast<D3D11_FEATURE_DATA_FORMAT_SUPPORT2*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + return GetFormatSupportFlags(info->InFormat, nullptr, &info->OutFormatSupport2); + } return S_OK; + + case D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x = TRUE; + } return S_OK; + + case D3D11_FEATURE_D3D11_OPTIONS: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404457(v=vs.85).aspx + const auto& features = m_dxvkDevice->features(); + + info->OutputMergerLogicOp = features.core.features.logicOp; + info->UAVOnlyRenderingForcedSampleCount = features.core.features.variableMultisampleRate; + info->DiscardAPIsSeenByDriver = TRUE; + info->FlagsForUpdateAndCopySeenByDriver = TRUE; + info->ClearView = TRUE; + info->CopyWithOverlap = TRUE; + info->ConstantBufferPartialUpdate = TRUE; + info->ConstantBufferOffsetting = TRUE; + info->MapNoOverwriteOnDynamicConstantBuffer = TRUE; + info->MapNoOverwriteOnDynamicBufferSRV = TRUE; + info->MultisampleRTVWithForcedSampleCountOne = TRUE; /* not really */ + info->SAD4ShaderInstructions = TRUE; + info->ExtendedDoublesShaderInstructions = TRUE; + info->ExtendedResourceSharing = TRUE; /* not really */ + } return S_OK; + + case D3D11_FEATURE_ARCHITECTURE_INFO: { + auto info = static_cast<D3D11_FEATURE_DATA_ARCHITECTURE_INFO*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->TileBasedDeferredRenderer = FALSE; + } return S_OK; + + case D3D11_FEATURE_D3D9_OPTIONS: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D9_OPTIONS*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->FullNonPow2TextureSupport = TRUE; + } return S_OK; + + case D3D11_FEATURE_SHADER_MIN_PRECISION_SUPPORT: { + auto info = static_cast<D3D11_FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + // Report that we only support full 32-bit operations + info->PixelShaderMinPrecision = 0; + info->AllOtherShaderStagesMinPrecision = 0; + } return S_OK; + + case D3D11_FEATURE_D3D9_SHADOW_SUPPORT: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->SupportsDepthAsTextureWithLessEqualComparisonFilter = TRUE; + } return S_OK; + + case D3D11_FEATURE_D3D11_OPTIONS1: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS1*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + // Min/Max filtering requires Tiled Resources Tier 2 for some reason, + // so we cannot support it even though Vulkan exposes this feature + info->TiledResourcesTier = D3D11_TILED_RESOURCES_NOT_SUPPORTED; + info->MinMaxFiltering = FALSE; + info->ClearViewAlsoSupportsDepthOnlyFormats = TRUE; + info->MapOnDefaultBuffers = TRUE; + } return S_OK; + + case D3D11_FEATURE_D3D9_SIMPLE_INSTANCING_SUPPORT: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->SimpleInstancingSupported = TRUE; + } return S_OK; + + case D3D11_FEATURE_MARKER_SUPPORT: { + auto info = static_cast<D3D11_FEATURE_DATA_MARKER_SUPPORT*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->Profile = FALSE; + } return S_OK; + + case D3D11_FEATURE_D3D9_OPTIONS1: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D9_OPTIONS1*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->FullNonPow2TextureSupported = TRUE; + info->DepthAsTextureWithLessEqualComparisonFilterSupported = TRUE; + info->SimpleInstancingSupported = TRUE; + info->TextureCubeFaceRenderTargetWithNonCubeDepthStencilSupported = TRUE; + } return S_OK; + + case D3D11_FEATURE_D3D11_OPTIONS2: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS2*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + const auto& extensions = m_dxvkDevice->extensions(); + const auto& features = m_dxvkDevice->features(); + + info->PSSpecifiedStencilRefSupported = extensions.extShaderStencilExport; + info->TypedUAVLoadAdditionalFormats = features.core.features.shaderStorageImageReadWithoutFormat; + info->ROVsSupported = FALSE; + info->ConservativeRasterizationTier = D3D11_CONSERVATIVE_RASTERIZATION_NOT_SUPPORTED; + info->MapOnDefaultTextures = TRUE; + info->TiledResourcesTier = D3D11_TILED_RESOURCES_NOT_SUPPORTED; + info->StandardSwizzle = FALSE; + info->UnifiedMemoryArchitecture = m_dxvkDevice->isUnifiedMemoryArchitecture(); + + if (m_dxvkDevice->extensions().extConservativeRasterization) { + // We don't have a way to query uncertainty regions, so just check degenerate triangle behaviour + info->ConservativeRasterizationTier = m_dxvkDevice->properties().extConservativeRasterization.degenerateTrianglesRasterized + ? D3D11_CONSERVATIVE_RASTERIZATION_TIER_2 : D3D11_CONSERVATIVE_RASTERIZATION_TIER_1; + } + } return S_OK; + + case D3D11_FEATURE_D3D11_OPTIONS3: { + if (FeatureSupportDataSize != sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS3)) + return E_INVALIDARG; + + const auto& extensions = m_dxvkDevice->extensions(); + + auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS3*>(pFeatureSupportData); + info->VPAndRTArrayIndexFromAnyShaderFeedingRasterizer = extensions.extShaderViewportIndexLayer; + } return S_OK; + + case D3D11_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT: { + auto info = static_cast<D3D11_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + // These numbers are not accurate, but it should not have any effect on D3D11 apps + info->MaxGPUVirtualAddressBitsPerResource = 32; + info->MaxGPUVirtualAddressBitsPerProcess = 40; + } return S_OK; + + case D3D11_FEATURE_D3D11_OPTIONS4: { + auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS4*>(pFeatureSupportData); + + if (FeatureSupportDataSize != sizeof(*info)) + return E_INVALIDARG; + + info->ExtendedNV12SharedTextureSupported = FALSE; + } return S_OK; + + default: + Logger::err(str::format("D3D11Device: CheckFeatureSupport: Unknown feature: ", Feature)); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::GetPrivateData( + REFGUID guid, UINT* pDataSize, void* pData) { + return m_container->GetPrivateData(guid, pDataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::SetPrivateData( + REFGUID guid, UINT DataSize, const void* pData) { + return m_container->SetPrivateData(guid, DataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::SetPrivateDataInterface( + REFGUID guid, const IUnknown* pData) { + return m_container->SetPrivateDataInterface(guid, pData); + } + + + D3D_FEATURE_LEVEL STDMETHODCALLTYPE D3D11Device::GetFeatureLevel() { + return m_featureLevel; + } + + + UINT STDMETHODCALLTYPE D3D11Device::GetCreationFlags() { + return m_featureFlags; + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::GetDeviceRemovedReason() { + VkResult status = m_dxvkDevice->getDeviceStatus(); + + switch (status) { + case VK_SUCCESS: return S_OK; + default: return DXGI_ERROR_DEVICE_RESET; + } + } + + + void STDMETHODCALLTYPE D3D11Device::GetImmediateContext(ID3D11DeviceContext** ppImmediateContext) { + *ppImmediateContext = m_context.ref(); + } + + + void STDMETHODCALLTYPE D3D11Device::GetImmediateContext1(ID3D11DeviceContext1** ppImmediateContext) { + *ppImmediateContext = m_context.ref(); + } + + + void STDMETHODCALLTYPE D3D11Device::GetImmediateContext2(ID3D11DeviceContext2** ppImmediateContext) { + *ppImmediateContext = m_context.ref(); + } + + + void STDMETHODCALLTYPE D3D11Device::GetImmediateContext3(ID3D11DeviceContext3** ppImmediateContext) { + *ppImmediateContext = m_context.ref(); + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::SetExceptionMode(UINT RaiseFlags) { + Logger::err("D3D11Device::SetExceptionMode: Not implemented"); + return E_NOTIMPL; + } + + + UINT STDMETHODCALLTYPE D3D11Device::GetExceptionMode() { + Logger::err("D3D11Device::GetExceptionMode: Not implemented"); + return 0; + } + + + void STDMETHODCALLTYPE D3D11Device::GetResourceTiling( + ID3D11Resource* pTiledResource, + UINT* pNumTilesForEntireResource, + D3D11_PACKED_MIP_DESC* pPackedMipDesc, + D3D11_TILE_SHAPE* pStandardTileShapeForNonPackedMips, + UINT* pNumSubresourceTilings, + UINT FirstSubresourceTilingToGet, + D3D11_SUBRESOURCE_TILING* pSubresourceTilingsForNonPackedMips) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11Device::GetResourceTiling: Tiled resources not supported"); + + if (pNumTilesForEntireResource) + *pNumTilesForEntireResource = 0; + + if (pPackedMipDesc) + *pPackedMipDesc = D3D11_PACKED_MIP_DESC(); + + if (pStandardTileShapeForNonPackedMips) + *pStandardTileShapeForNonPackedMips = D3D11_TILE_SHAPE(); + + if (pNumSubresourceTilings) { + if (pSubresourceTilingsForNonPackedMips) { + for (uint32_t i = 0; i < *pNumSubresourceTilings; i++) + pSubresourceTilingsForNonPackedMips[i] = D3D11_SUBRESOURCE_TILING(); + } + + *pNumSubresourceTilings = 0; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11Device::RegisterDeviceRemovedEvent( + HANDLE hEvent, + DWORD* pdwCookie) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11Device::RegisterDeviceRemovedEvent: Not implemented"); + + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11Device::UnregisterDeviceRemoved( + DWORD dwCookie) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11Device::UnregisterDeviceRemovedEvent: Not implemented"); + } + + + DXGI_VK_FORMAT_INFO D3D11Device::LookupFormat( + DXGI_FORMAT Format, + DXGI_VK_FORMAT_MODE Mode) const { + return m_d3d11Formats.GetFormatInfo(Format, Mode); + } + + + DXGI_VK_FORMAT_INFO D3D11Device::LookupPackedFormat( + DXGI_FORMAT Format, + DXGI_VK_FORMAT_MODE Mode) const { + return m_d3d11Formats.GetPackedFormatInfo(Format, Mode); + } + + + DXGI_VK_FORMAT_FAMILY D3D11Device::LookupFamily( + DXGI_FORMAT Format, + DXGI_VK_FORMAT_MODE Mode) const { + return m_d3d11Formats.GetFormatFamily(Format, Mode); + } + + + void D3D11Device::FlushInitContext() { + m_initializer->Flush(); + } + + + bool D3D11Device::CheckFeatureLevelSupport( + const Rc<DxvkInstance>& instance, + const Rc<DxvkAdapter>& adapter, + D3D_FEATURE_LEVEL featureLevel) { + if (featureLevel > GetMaxFeatureLevel(instance)) + return false; + + // Check whether all features are supported + const DxvkDeviceFeatures features + = GetDeviceFeatures(adapter, featureLevel); + + if (!adapter->checkFeatureSupport(features)) + return false; + + // TODO also check for required limits + return true; + } + + + DxvkDeviceFeatures D3D11Device::GetDeviceFeatures( + const Rc<DxvkAdapter>& adapter, + D3D_FEATURE_LEVEL featureLevel) { + DxvkDeviceFeatures supported = adapter->features(); + DxvkDeviceFeatures enabled = {}; + +#ifndef VBOX + enabled.core.features.geometryShader = VK_TRUE; +#else + enabled.core.features.geometryShader = supported.core.features.geometryShader; +#endif + enabled.core.features.robustBufferAccess = VK_TRUE; + enabled.core.features.shaderStorageImageWriteWithoutFormat = VK_TRUE; + enabled.core.features.depthBounds = supported.core.features.depthBounds; + + enabled.shaderDrawParameters.shaderDrawParameters = VK_TRUE; + + enabled.extMemoryPriority.memoryPriority = supported.extMemoryPriority.memoryPriority; + + enabled.extRobustness2.robustBufferAccess2 = supported.extRobustness2.robustBufferAccess2; + enabled.extRobustness2.robustImageAccess2 = supported.extRobustness2.robustImageAccess2; + enabled.extRobustness2.nullDescriptor = supported.extRobustness2.nullDescriptor; + + enabled.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation = supported.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation; + + enabled.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor = supported.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor; + enabled.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor = supported.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor; + + if (supported.extCustomBorderColor.customBorderColorWithoutFormat) { + enabled.extCustomBorderColor.customBorderColors = VK_TRUE; + enabled.extCustomBorderColor.customBorderColorWithoutFormat = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_9_1) { + enabled.core.features.depthClamp = VK_TRUE; + enabled.core.features.depthBiasClamp = VK_TRUE; + enabled.core.features.fillModeNonSolid = VK_TRUE; + enabled.core.features.pipelineStatisticsQuery = supported.core.features.pipelineStatisticsQuery; + enabled.core.features.sampleRateShading = VK_TRUE; + enabled.core.features.samplerAnisotropy = supported.core.features.samplerAnisotropy; + enabled.core.features.shaderClipDistance = VK_TRUE; +#ifndef VBOX + enabled.core.features.shaderCullDistance = VK_TRUE; +#else + enabled.core.features.shaderCullDistance = supported.core.features.shaderCullDistance; +#endif + enabled.core.features.textureCompressionBC = VK_TRUE; + enabled.extDepthClipEnable.depthClipEnable = supported.extDepthClipEnable.depthClipEnable; + enabled.extHostQueryReset.hostQueryReset = supported.extHostQueryReset.hostQueryReset; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_9_2) { + enabled.core.features.occlusionQueryPrecise = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_9_3) { + enabled.core.features.independentBlend = VK_TRUE; + enabled.core.features.multiViewport = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_10_0) { + enabled.core.features.fullDrawIndexUint32 = VK_TRUE; + enabled.core.features.logicOp = supported.core.features.logicOp; + enabled.core.features.shaderImageGatherExtended = VK_TRUE; + enabled.core.features.variableMultisampleRate = supported.core.features.variableMultisampleRate; +#ifndef VBOX + enabled.extTransformFeedback.transformFeedback = VK_TRUE; +#else + enabled.extTransformFeedback.transformFeedback = supported.extTransformFeedback.transformFeedback; +#endif + enabled.extTransformFeedback.geometryStreams = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_10_1) { + enabled.core.features.dualSrcBlend = VK_TRUE; + enabled.core.features.imageCubeArray = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_11_0) { + enabled.core.features.drawIndirectFirstInstance = VK_TRUE; + enabled.core.features.fragmentStoresAndAtomics = VK_TRUE; + enabled.core.features.multiDrawIndirect = VK_TRUE; + enabled.core.features.shaderFloat64 = supported.core.features.shaderFloat64; + enabled.core.features.shaderInt64 = supported.core.features.shaderInt64; + enabled.core.features.shaderStorageImageReadWithoutFormat = supported.core.features.shaderStorageImageReadWithoutFormat; +#ifndef VBOX + enabled.core.features.tessellationShader = VK_TRUE; +#else + enabled.core.features.tessellationShader = supported.core.features.tessellationShader; +#endif + } + + if (featureLevel >= D3D_FEATURE_LEVEL_11_1) { + enabled.core.features.logicOp = VK_TRUE; + enabled.core.features.variableMultisampleRate = VK_TRUE; + enabled.core.features.vertexPipelineStoresAndAtomics = VK_TRUE; + } + + return enabled; + } + + + HRESULT D3D11Device::CreateShaderModule( + D3D11CommonShader* pShaderModule, + DxvkShaderKey ShaderKey, + const void* pShaderBytecode, + size_t BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + const DxbcModuleInfo* pModuleInfo) { + if (pClassLinkage != nullptr) + Logger::warn("D3D11Device::CreateShaderModule: Class linkage not supported"); + + D3D11CommonShader commonShader; + + HRESULT hr = m_shaderModules.GetShaderModule(this, + &ShaderKey, pModuleInfo, pShaderBytecode, BytecodeLength, + &commonShader); + + if (FAILED(hr)) + return hr; + + auto shader = commonShader.GetShader(); + + if (shader->flags().test(DxvkShaderFlag::ExportsStencilRef) + && !m_dxvkDevice->extensions().extShaderStencilExport) + return E_INVALIDARG; + + if (shader->flags().test(DxvkShaderFlag::ExportsViewportIndexLayerFromVertexStage) + && !m_dxvkDevice->extensions().extShaderViewportIndexLayer) + return E_INVALIDARG; + + *pShaderModule = std::move(commonShader); + return S_OK; + } + + + HRESULT D3D11Device::GetFormatSupportFlags(DXGI_FORMAT Format, UINT* pFlags1, UINT* pFlags2) const { + const DXGI_VK_FORMAT_INFO fmtMapping = LookupFormat(Format, DXGI_VK_FORMAT_MODE_ANY); + + // Reset output flags preemptively + if (pFlags1 != nullptr) *pFlags1 = 0; + if (pFlags2 != nullptr) *pFlags2 = 0; + + // Unsupported or invalid format + if (Format != DXGI_FORMAT_UNKNOWN && fmtMapping.Format == VK_FORMAT_UNDEFINED) + return E_FAIL; + + // Query Vulkan format properties and supported features for it + const DxvkFormatInfo* fmtProperties = imageFormatInfo(fmtMapping.Format); + + VkFormatProperties fmtSupport = fmtMapping.Format != VK_FORMAT_UNDEFINED + ? m_dxvkAdapter->formatProperties(fmtMapping.Format) + : VkFormatProperties(); + + VkFormatFeatureFlags bufFeatures = fmtSupport.bufferFeatures; + VkFormatFeatureFlags imgFeatures = fmtSupport.optimalTilingFeatures | fmtSupport.linearTilingFeatures; + + // For multi-plane images, we want to check available view formats as well + if (fmtProperties->flags.test(DxvkFormatFlag::MultiPlane)) { + const VkFormatFeatureFlags featureMask + = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT + | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT + | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT + | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT + | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; + + DXGI_VK_FORMAT_FAMILY formatFamily = LookupFamily(Format, DXGI_VK_FORMAT_MODE_ANY); + + for (uint32_t i = 0; i < formatFamily.FormatCount; i++) { + VkFormatProperties viewFmtSupport = m_dxvkAdapter->formatProperties(formatFamily.Formats[i]); + imgFeatures |= (viewFmtSupport.optimalTilingFeatures | viewFmtSupport.linearTilingFeatures) & featureMask; + } + } + + UINT flags1 = 0; + UINT flags2 = 0; + + // Format can be used for shader resource views with buffers + if (bufFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT + || Format == DXGI_FORMAT_UNKNOWN) + flags1 |= D3D11_FORMAT_SUPPORT_BUFFER; + + // Format can be used for vertex data + if (bufFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) + flags1 |= D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER; + + // Format can be used for index data. Only + // these two formats are supported by D3D11. + if (Format == DXGI_FORMAT_R16_UINT + || Format == DXGI_FORMAT_R32_UINT) + flags1 |= D3D11_FORMAT_SUPPORT_IA_INDEX_BUFFER; + + // These formats are technically irrelevant since + // SO buffers are passed in as raw buffers and not + // as views, but the feature flag exists regardless + if (Format == DXGI_FORMAT_R32_FLOAT + || Format == DXGI_FORMAT_R32_UINT + || Format == DXGI_FORMAT_R32_SINT + || Format == DXGI_FORMAT_R32G32_FLOAT + || Format == DXGI_FORMAT_R32G32_UINT + || Format == DXGI_FORMAT_R32G32_SINT + || Format == DXGI_FORMAT_R32G32B32_FLOAT + || Format == DXGI_FORMAT_R32G32B32_UINT + || Format == DXGI_FORMAT_R32G32B32_SINT + || Format == DXGI_FORMAT_R32G32B32A32_FLOAT + || Format == DXGI_FORMAT_R32G32B32A32_UINT + || Format == DXGI_FORMAT_R32G32B32A32_SINT) + flags1 |= D3D11_FORMAT_SUPPORT_SO_BUFFER; + + if (imgFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT + || imgFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) { + const VkFormat depthFormat = LookupFormat(Format, DXGI_VK_FORMAT_MODE_DEPTH).Format; + + if (GetImageTypeSupport(fmtMapping.Format, VK_IMAGE_TYPE_1D)) flags1 |= D3D11_FORMAT_SUPPORT_TEXTURE1D; + if (GetImageTypeSupport(fmtMapping.Format, VK_IMAGE_TYPE_2D)) flags1 |= D3D11_FORMAT_SUPPORT_TEXTURE2D; + if (GetImageTypeSupport(fmtMapping.Format, VK_IMAGE_TYPE_3D)) flags1 |= D3D11_FORMAT_SUPPORT_TEXTURE3D; + + flags1 |= D3D11_FORMAT_SUPPORT_MIP + | D3D11_FORMAT_SUPPORT_CAST_WITHIN_BIT_LAYOUT; + + // Format can be read + if (imgFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { + flags1 |= D3D11_FORMAT_SUPPORT_TEXTURECUBE + | D3D11_FORMAT_SUPPORT_SHADER_LOAD + | D3D11_FORMAT_SUPPORT_SHADER_GATHER + | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE + | D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_INPUT; + + if (depthFormat != VK_FORMAT_UNDEFINED) { + flags1 |= D3D11_FORMAT_SUPPORT_SHADER_GATHER_COMPARISON + | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE_COMPARISON; + } + } + + // Format is a color format that can be used for rendering + if (imgFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { + flags1 |= D3D11_FORMAT_SUPPORT_RENDER_TARGET + | D3D11_FORMAT_SUPPORT_MIP_AUTOGEN + | D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT; + + if (m_dxvkDevice->features().core.features.logicOp) + flags2 |= D3D11_FORMAT_SUPPORT2_OUTPUT_MERGER_LOGIC_OP; + } + + // Format supports blending when used for rendering + if (imgFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT) + flags1 |= D3D11_FORMAT_SUPPORT_BLENDABLE; + + // Format is a depth-stencil format that can be used for rendering + if (imgFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) + flags1 |= D3D11_FORMAT_SUPPORT_DEPTH_STENCIL; + + // FIXME implement properly. This would require a VkSurface. + if (Format == DXGI_FORMAT_R8G8B8A8_UNORM + || Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB + || Format == DXGI_FORMAT_B8G8R8A8_UNORM + || Format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB + || Format == DXGI_FORMAT_R16G16B16A16_FLOAT + || Format == DXGI_FORMAT_R10G10B10A2_UNORM + || Format == DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM) + flags1 |= D3D11_FORMAT_SUPPORT_DISPLAY; + + // Query multisample support for this format + VkImageFormatProperties imgFmtProperties; + + VkResult status = m_dxvkAdapter->imageFormatProperties(fmtMapping.Format, + VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + (fmtProperties->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) + ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + : VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + 0, imgFmtProperties); + + if (status == VK_SUCCESS && imgFmtProperties.sampleCounts > VK_SAMPLE_COUNT_1_BIT) { + flags1 |= D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET + | D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE + | D3D11_FORMAT_SUPPORT_MULTISAMPLE_LOAD; + } + } + + // Format can be used for storage images or storage texel buffers + if ((bufFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) + && (imgFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { + flags1 |= D3D11_FORMAT_SUPPORT_TYPED_UNORDERED_ACCESS_VIEW; + flags2 |= D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE; + + if (m_dxvkDevice->features().core.features.shaderStorageImageReadWithoutFormat + || Format == DXGI_FORMAT_R32_UINT + || Format == DXGI_FORMAT_R32_SINT + || Format == DXGI_FORMAT_R32_FLOAT) + flags2 |= D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD; + + if (Format == DXGI_FORMAT_R32_UINT + || Format == DXGI_FORMAT_R32_SINT) { + flags2 |= D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_ADD + | D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS + | D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE + | D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE; + } + + if (Format == DXGI_FORMAT_R32_SINT) + flags2 |= D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX; + + if (Format == DXGI_FORMAT_R32_UINT) + flags2 |= D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX; + } + + // Mark everyting as CPU lockable + if (flags1 | flags2) + flags1 |= D3D11_FORMAT_SUPPORT_CPU_LOCKABLE; + + // Write back format support flags + if (pFlags1 != nullptr) *pFlags1 = flags1; + if (pFlags2 != nullptr) *pFlags2 = flags2; + return (pFlags1 && flags1) || (pFlags2 && flags2) ? S_OK : E_FAIL; + } + + + BOOL D3D11Device::GetImageTypeSupport(VkFormat Format, VkImageType Type) const { + VkImageFormatProperties props; + + VkResult status = m_dxvkAdapter->imageFormatProperties( + Format, Type, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_SAMPLED_BIT, 0, props); + + if (status != VK_SUCCESS) { + status = m_dxvkAdapter->imageFormatProperties( + Format, Type, VK_IMAGE_TILING_LINEAR, + VK_IMAGE_USAGE_SAMPLED_BIT, 0, props); + } + + return status == VK_SUCCESS; + } + + + uint32_t D3D11Device::GetViewPlaneIndex( + ID3D11Resource* pResource, + DXGI_FORMAT ViewFormat) { + auto texture = GetCommonTexture(pResource); + + if (!texture) + return 0; + + uint32_t planeCount = texture->GetPlaneCount(); + + if (planeCount == 1) + return 0; + + auto formatMode = texture->GetFormatMode(); + auto formatFamily = LookupFamily(texture->Desc()->Format, formatMode); + auto viewFormat = LookupFormat(ViewFormat, formatMode); + + for (uint32_t i = 0; i < formatFamily.FormatCount; i++) { + if (formatFamily.Formats[i] == viewFormat.Format) + return i % planeCount; + } + + return ~0u; + } + + + template<typename Void> + void D3D11Device::CopySubresourceData( + Void* pData, + UINT RowPitch, + UINT DepthPitch, + ID3D11Resource* pResource, + UINT Subresource, + const D3D11_BOX* pBox) { + auto texture = GetCommonTexture(pResource); + + if (!texture) + return; + + // Validate texture state and skip invalid calls + if (texture->Desc()->Usage != D3D11_USAGE_DEFAULT + || texture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_NONE + || texture->CountSubresources() <= Subresource + || texture->GetMapType(Subresource) == D3D11_MAP(~0u)) + return; + + // Retrieve image format information + VkFormat packedFormat = LookupPackedFormat( + texture->Desc()->Format, + texture->GetFormatMode()).Format; + + auto formatInfo = imageFormatInfo(packedFormat); + + // Validate box against subresource dimensions + Rc<DxvkImage> image = texture->GetImage(); + + auto subresource = texture->GetSubresourceFromIndex( + formatInfo->aspectMask, Subresource); + + VkOffset3D offset = { 0, 0, 0 }; + VkExtent3D extent = image->mipLevelExtent(subresource.mipLevel); + + if (pBox) { + if (pBox->left >= pBox->right + || pBox->top >= pBox->bottom + || pBox->front >= pBox->back) + return; // legal, but no-op + + if (pBox->right > extent.width + || pBox->bottom > extent.height + || pBox->back > extent.depth) + return; // out of bounds + + offset = VkOffset3D { + int32_t(pBox->left), + int32_t(pBox->top), + int32_t(pBox->front) }; + + extent = VkExtent3D { + pBox->right - pBox->left, + pBox->bottom - pBox->top, + pBox->back - pBox->front }; + } + + // We can only operate on full blocks of compressed images + offset = util::computeBlockOffset(offset, formatInfo->blockSize); + extent = util::computeBlockCount(extent, formatInfo->blockSize); + + // Determine the memory layout of the image data + D3D11_MAPPED_SUBRESOURCE subresourceData = { }; + + if (texture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) { + VkSubresourceLayout layout = image->querySubresourceLayout(subresource); + subresourceData.pData = image->mapPtr(layout.offset); + subresourceData.RowPitch = layout.rowPitch; + subresourceData.DepthPitch = layout.depthPitch; + } else { + subresourceData.pData = texture->GetMappedBuffer(Subresource)->mapPtr(0); + subresourceData.RowPitch = formatInfo->elementSize * extent.width; + subresourceData.DepthPitch = formatInfo->elementSize * extent.width * extent.height; + } + + if constexpr (std::is_const<Void>::value) { + // WriteToSubresource + auto src = reinterpret_cast<const char*>(pData); + auto dst = reinterpret_cast< char*>(subresourceData.pData); + + for (uint32_t z = 0; z < extent.depth; z++) { + for (uint32_t y = 0; y < extent.height; y++) { + std::memcpy( + dst + (offset.z + z) * subresourceData.DepthPitch + + (offset.y + y) * subresourceData.RowPitch + + (offset.x) * formatInfo->elementSize, + src + z * DepthPitch + + y * RowPitch, + formatInfo->elementSize * extent.width); + } + } + } else { + // ReadFromSubresource + auto src = reinterpret_cast<const char*>(subresourceData.pData); + auto dst = reinterpret_cast< char*>(pData); + + for (uint32_t z = 0; z < extent.depth; z++) { + for (uint32_t y = 0; y < extent.height; y++) { + std::memcpy( + dst + z * DepthPitch + + y * RowPitch, + src + (offset.z + z) * subresourceData.DepthPitch + + (offset.y + y) * subresourceData.RowPitch + + (offset.x) * formatInfo->elementSize, + formatInfo->elementSize * extent.width); + } + } + } + } + + + D3D_FEATURE_LEVEL D3D11Device::GetMaxFeatureLevel(const Rc<DxvkInstance>& pInstance) { + static const std::array<std::pair<std::string, D3D_FEATURE_LEVEL>, 9> s_featureLevels = {{ + { "12_1", D3D_FEATURE_LEVEL_12_1 }, + { "12_0", D3D_FEATURE_LEVEL_12_0 }, + { "11_1", D3D_FEATURE_LEVEL_11_1 }, + { "11_0", D3D_FEATURE_LEVEL_11_0 }, + { "10_1", D3D_FEATURE_LEVEL_10_1 }, + { "10_0", D3D_FEATURE_LEVEL_10_0 }, + { "9_3", D3D_FEATURE_LEVEL_9_3 }, + { "9_2", D3D_FEATURE_LEVEL_9_2 }, + { "9_1", D3D_FEATURE_LEVEL_9_1 }, + }}; + + const std::string maxLevel = pInstance->config() + .getOption<std::string>("d3d11.maxFeatureLevel"); + + auto entry = std::find_if(s_featureLevels.begin(), s_featureLevels.end(), + [&] (const std::pair<std::string, D3D_FEATURE_LEVEL>& pair) { + return pair.first == maxLevel; + }); + + return entry != s_featureLevels.end() + ? entry->second + : D3D_FEATURE_LEVEL_11_1; + } + + + + + D3D11DeviceExt::D3D11DeviceExt( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice) + : m_container(pContainer), m_device(pDevice) { + + } + + + ULONG STDMETHODCALLTYPE D3D11DeviceExt::AddRef() { + return m_container->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11DeviceExt::Release() { + return m_container->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11DeviceExt::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_container->QueryInterface(riid, ppvObject); + } + + + BOOL STDMETHODCALLTYPE D3D11DeviceExt::GetExtensionSupport( + D3D11_VK_EXTENSION Extension) { + const auto& deviceFeatures = m_device->GetDXVKDevice()->features(); + const auto& deviceExtensions = m_device->GetDXVKDevice()->extensions(); + + switch (Extension) { + case D3D11_VK_EXT_BARRIER_CONTROL: + return true; + + case D3D11_VK_EXT_MULTI_DRAW_INDIRECT: + return deviceFeatures.core.features.multiDrawIndirect; + + case D3D11_VK_EXT_MULTI_DRAW_INDIRECT_COUNT: + return deviceFeatures.core.features.multiDrawIndirect + && deviceExtensions.khrDrawIndirectCount; + + case D3D11_VK_EXT_DEPTH_BOUNDS: + return deviceFeatures.core.features.depthBounds; + + case D3D11_VK_NVX_IMAGE_VIEW_HANDLE: + return deviceExtensions.nvxImageViewHandle; + + case D3D11_VK_NVX_BINARY_IMPORT: + return deviceExtensions.nvxBinaryImport + && deviceExtensions.khrBufferDeviceAddress; + + default: + return false; + } + } + + + bool STDMETHODCALLTYPE D3D11DeviceExt::GetCudaTextureObjectNVX(uint32_t srvDriverHandle, uint32_t samplerDriverHandle, uint32_t* pCudaTextureHandle) { + ID3D11ShaderResourceView* srv = HandleToSrvNVX(srvDriverHandle); + + if (!srv) { + Logger::warn(str::format("GetCudaTextureObjectNVX() failure - srv handle wasn't found: ", srvDriverHandle)); + return false; + } + + ID3D11SamplerState* samplerState = HandleToSamplerNVX(samplerDriverHandle); + + if (!samplerState) { + Logger::warn(str::format("GetCudaTextureObjectNVX() failure - sampler handle wasn't found: ", samplerDriverHandle)); + return false; + } + + D3D11SamplerState* pSS = static_cast<D3D11SamplerState*>(samplerState); + Rc<DxvkSampler> pDSS = pSS->GetDXVKSampler(); + VkSampler vkSampler = pDSS->handle(); + + D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(srv); + Rc<DxvkImageView> pIV = pSRV->GetImageView(); + VkImageView vkImageView = pIV->handle(); + + VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX}; + imageViewHandleInfo.imageView = vkImageView; + imageViewHandleInfo.sampler = vkSampler; + imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + + // note: there's no implicit lifetime management here; it's up to the + // app to keep the sampler and SRV alive as long as it wants to use this + // derived handle. + VkDevice vkDevice = m_device->GetDXVKDevice()->handle(); + *pCudaTextureHandle = m_device->GetDXVKDevice()->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo); + + if (!*pCudaTextureHandle) { + Logger::warn("GetCudaTextureObjectNVX() handle==0 - failed"); + return false; + } + + return true; + } + + + bool STDMETHODCALLTYPE D3D11DeviceExt::CreateCubinComputeShaderWithNameNVX(const void* pCubin, uint32_t size, + uint32_t blockX, uint32_t blockY, uint32_t blockZ, const char* pShaderName, IUnknown** phShader) { + Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice(); + VkDevice vkDevice = dxvkDevice->handle(); + + VkCuModuleCreateInfoNVX moduleCreateInfo = { VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX }; + moduleCreateInfo.pData = pCubin; + moduleCreateInfo.dataSize = size; + + VkCuModuleNVX cuModule; + VkCuFunctionNVX cuFunction; + VkResult result; + + if ((result = dxvkDevice->vkd()->vkCreateCuModuleNVX(vkDevice, &moduleCreateInfo, nullptr, &cuModule))) { + Logger::warn(str::format("CreateCubinComputeShaderWithNameNVX() - failure to create module - result=", result, " pcubindata=", pCubin, " cubinsize=", size)); + return false; // failure + } + + VkCuFunctionCreateInfoNVX functionCreateInfo = { VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX }; + functionCreateInfo.module = cuModule; + functionCreateInfo.pName = pShaderName; + + if ((result = dxvkDevice->vkd()->vkCreateCuFunctionNVX(vkDevice, &functionCreateInfo, nullptr, &cuFunction))) { + dxvkDevice->vkd()->vkDestroyCuModuleNVX(vkDevice, cuModule, nullptr); + Logger::warn(str::format("CreateCubinComputeShaderWithNameNVX() - failure to create function - result=", result)); + return false; + } + + *phShader = ref(new CubinShaderWrapper(dxvkDevice, + cuModule, cuFunction, { blockX, blockY, blockZ })); + return true; + } + + + bool STDMETHODCALLTYPE D3D11DeviceExt::GetResourceHandleGPUVirtualAddressAndSizeNVX(void* hObject, uint64_t* gpuVAStart, uint64_t* gpuVASize) { + // The hObject 'opaque driver handle' is really just a straight cast + // of the corresponding ID3D11Resource* in dxvk/dxvknvapi + ID3D11Resource* pResource = static_cast<ID3D11Resource*>(hObject); + + D3D11_COMMON_RESOURCE_DESC resourceDesc; + if (FAILED(GetCommonResourceDesc(pResource, &resourceDesc))) { + Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - GetCommonResourceDesc() failed"); + return false; + } + + switch (resourceDesc.Dim) { + case D3D11_RESOURCE_DIMENSION_BUFFER: + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + // okay - we can deal with those two dimensions + break; + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + case D3D11_RESOURCE_DIMENSION_UNKNOWN: + default: + Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - failure - unsupported dimension: ", resourceDesc.Dim)); + return false; + } + + Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice(); + VkDevice vkDevice = dxvkDevice->handle(); + + if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) { + D3D11CommonTexture *texture = GetCommonTexture(pResource); + Rc<DxvkImage> dxvkImage = texture->GetImage(); + if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) { + Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(res=", pResource,") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure")); + return false; + } + + // The d3d11 nvapi provides us a texture but vulkan only lets us get the GPU address from an imageview. So, make a private imageview and get the address from that... + + D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; + + const D3D11_COMMON_TEXTURE_DESC *texDesc = texture->Desc(); + if (texDesc->ArraySize != 1) { + Logger::debug(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - unexpected array size: ", texDesc->ArraySize)); + } + resourceViewDesc.Format = texDesc->Format; + resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + resourceViewDesc.Texture2D.MostDetailedMip = 0; + resourceViewDesc.Texture2D.MipLevels = texDesc->MipLevels; + + Com<ID3D11ShaderResourceView> pNewSRV; + HRESULT hr = m_device->CreateShaderResourceView(pResource, &resourceViewDesc, &pNewSRV); + if (FAILED(hr)) { + Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - private CreateShaderResourceView() failed"); + return false; + } + + Rc<DxvkImageView> dxvkImageView = static_cast<D3D11ShaderResourceView*>(pNewSRV.ptr())->GetImageView(); + VkImageView vkImageView = dxvkImageView->handle(); + + VkImageViewAddressPropertiesNVX imageViewAddressProperties = {VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX}; + + VkResult res = dxvkDevice->vkd()->vkGetImageViewAddressNVX(vkDevice, vkImageView, &imageViewAddressProperties); + if (res != VK_SUCCESS) { + Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): vkGetImageViewAddressNVX() result is failure: ", res)); + return false; + } + + *gpuVAStart = imageViewAddressProperties.deviceAddress; + *gpuVASize = imageViewAddressProperties.size; + } + else if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) { + D3D11Buffer *buffer = GetCommonBuffer(pResource); + const DxvkBufferSliceHandle bufSliceHandle = buffer->GetBuffer()->getSliceHandle(); + VkBuffer vkBuffer = bufSliceHandle.handle; + + VkBufferDeviceAddressInfoKHR bdaInfo = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR }; + bdaInfo.buffer = vkBuffer; + VkDeviceAddress bufAddr = dxvkDevice->vkd()->vkGetBufferDeviceAddressKHR(vkDevice, &bdaInfo); + *gpuVAStart = uint64_t(bufAddr) + bufSliceHandle.offset; + *gpuVASize = bufSliceHandle.length; + } + + if (!*gpuVAStart) + Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() addr==0 - unexpected"); // ... but not explicitly a failure; continue + + return true; + } + + + bool STDMETHODCALLTYPE D3D11DeviceExt::CreateUnorderedAccessViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAV, uint32_t* pDriverHandle) { + D3D11_COMMON_RESOURCE_DESC resourceDesc; + if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) { + Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed"); + return false; + } + if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) { + Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim)); + return false; + } + + auto texture = GetCommonTexture(pResource); + Rc<DxvkImage> dxvkImage = texture->GetImage(); + if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) { + Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure")); + return false; + } + + if (!SUCCEEDED(m_device->CreateUnorderedAccessView(pResource, pDesc, ppUAV))) { + return false; + } + + D3D11UnorderedAccessView *pUAV = static_cast<D3D11UnorderedAccessView *>(*ppUAV); + Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice(); + VkDevice vkDevice = dxvkDevice->handle(); + + VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX}; + Rc<DxvkImageView> dxvkImageView = pUAV->GetImageView(); + VkImageView vkImageView = dxvkImageView->handle(); + + imageViewHandleInfo.imageView = vkImageView; + imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + + *pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo); + + if (!*pDriverHandle) { + Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() handle==0 - failure"); + pUAV->Release(); + return false; + } + + return true; + } + + + bool STDMETHODCALLTYPE D3D11DeviceExt::CreateShaderResourceViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRV, uint32_t* pDriverHandle) { + D3D11_COMMON_RESOURCE_DESC resourceDesc; + if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) { + Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed"); + return false; + } + if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) { + Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim)); + return false; + } + + auto texture = GetCommonTexture(pResource); + Rc<DxvkImage> dxvkImage = texture->GetImage(); + if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) { + Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure")); + return false; + } + + if (!SUCCEEDED(m_device->CreateShaderResourceView(pResource, pDesc, ppSRV))) { + return false; + } + + D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(*ppSRV); + Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice(); + VkDevice vkDevice = dxvkDevice->handle(); + + VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX}; + Rc<DxvkImageView> dxvkImageView = pSRV->GetImageView(); + VkImageView vkImageView = dxvkImageView->handle(); + + imageViewHandleInfo.imageView = vkImageView; + imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + + *pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo); + + if (!*pDriverHandle) { + Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() handle==0 - failure"); + pSRV->Release(); + return false; + } + + // will need to look-up resource from uint32 handle later + AddSrvAndHandleNVX(*ppSRV, *pDriverHandle); + return true; + } + + + bool STDMETHODCALLTYPE D3D11DeviceExt::CreateSamplerStateAndGetDriverHandleNVX(const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState, uint32_t* pDriverHandle) { + if (!SUCCEEDED(m_device->CreateSamplerState(pSamplerDesc, ppSamplerState))) { + return false; + } + + // for our purposes the actual value doesn't matter, only its uniqueness + static std::atomic<ULONG> s_seqNum = 0; + *pDriverHandle = ++s_seqNum; + + // will need to look-up sampler from uint32 handle later + AddSamplerAndHandleNVX(*ppSamplerState, *pDriverHandle); + return true; + } + + + void D3D11DeviceExt::AddSamplerAndHandleNVX(ID3D11SamplerState* pSampler, uint32_t Handle) { + std::lock_guard lock(m_mapLock); + m_samplerHandleToPtr[Handle] = pSampler; + } + + + ID3D11SamplerState* D3D11DeviceExt::HandleToSamplerNVX(uint32_t Handle) { + std::lock_guard lock(m_mapLock); + auto got = m_samplerHandleToPtr.find(Handle); + + if (got == m_samplerHandleToPtr.end()) + return nullptr; + + return static_cast<ID3D11SamplerState*>(got->second); + } + + + void D3D11DeviceExt::AddSrvAndHandleNVX(ID3D11ShaderResourceView* pSrv, uint32_t Handle) { + std::lock_guard lock(m_mapLock); + m_srvHandleToPtr[Handle] = pSrv; + } + + + ID3D11ShaderResourceView* D3D11DeviceExt::HandleToSrvNVX(uint32_t Handle) { + std::lock_guard lock(m_mapLock); + auto got = m_srvHandleToPtr.find(Handle); + + if (got == m_srvHandleToPtr.end()) + return nullptr; + + return static_cast<ID3D11ShaderResourceView*>(got->second); + } + + + + + + D3D11VideoDevice::D3D11VideoDevice( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice) + : m_container(pContainer), m_device(pDevice) { + + } + + + D3D11VideoDevice::~D3D11VideoDevice() { + + } + + + ULONG STDMETHODCALLTYPE D3D11VideoDevice::AddRef() { + return m_container->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11VideoDevice::Release() { + return m_container->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_container->QueryInterface(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoDecoder( + const D3D11_VIDEO_DECODER_DESC* pVideoDesc, + const D3D11_VIDEO_DECODER_CONFIG* pConfig, + ID3D11VideoDecoder** ppDecoder) { + Logger::err("D3D11VideoDevice::CreateVideoDecoder: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoProcessor( + ID3D11VideoProcessorEnumerator* pEnum, + UINT RateConversionIndex, + ID3D11VideoProcessor** ppVideoProcessor) { + try { + auto enumerator = static_cast<D3D11VideoProcessorEnumerator*>(pEnum); + *ppVideoProcessor = ref(new D3D11VideoProcessor(m_device, enumerator, RateConversionIndex)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_FAIL; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateAuthenticatedChannel( + D3D11_AUTHENTICATED_CHANNEL_TYPE ChannelType, + ID3D11AuthenticatedChannel** ppAuthenticatedChannel) { + Logger::err("D3D11VideoDevice::CreateAuthenticatedChannel: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateCryptoSession( + const GUID* pCryptoType, + const GUID* pDecoderProfile, + const GUID* pKeyExchangeType, + ID3D11CryptoSession** ppCryptoSession) { + Logger::err("D3D11VideoDevice::CreateCryptoSession: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoDecoderOutputView( + ID3D11Resource* pResource, + const D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC* pDesc, + ID3D11VideoDecoderOutputView** ppVDOVView) { + Logger::err("D3D11VideoDevice::CreateVideoDecoderOutputView: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoProcessorInputView( + ID3D11Resource* pResource, + ID3D11VideoProcessorEnumerator* pEnum, + const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC* pDesc, + ID3D11VideoProcessorInputView** ppVPIView) { + try { + *ppVPIView = ref(new D3D11VideoProcessorInputView(m_device, pResource, *pDesc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_FAIL; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoProcessorOutputView( + ID3D11Resource* pResource, + ID3D11VideoProcessorEnumerator* pEnum, + const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc, + ID3D11VideoProcessorOutputView** ppVPOView) { + try { + *ppVPOView = ref(new D3D11VideoProcessorOutputView(m_device, pResource, *pDesc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_FAIL; + } + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoProcessorEnumerator( + const D3D11_VIDEO_PROCESSOR_CONTENT_DESC* pDesc, + ID3D11VideoProcessorEnumerator** ppEnum) { + try { + *ppEnum = ref(new D3D11VideoProcessorEnumerator(m_device, *pDesc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_FAIL; + } + } + + + UINT STDMETHODCALLTYPE D3D11VideoDevice::GetVideoDecoderProfileCount() { + Logger::err("D3D11VideoDevice::GetVideoDecoderProfileCount: Stub"); + return 0; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::GetVideoDecoderProfile( + UINT Index, + GUID* pDecoderProfile) { + Logger::err("D3D11VideoDevice::GetVideoDecoderProfile: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CheckVideoDecoderFormat( + const GUID* pDecoderProfile, + DXGI_FORMAT Format, + BOOL* pSupported) { + Logger::err("D3D11VideoDevice::CheckVideoDecoderFormat: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::GetVideoDecoderConfigCount( + const D3D11_VIDEO_DECODER_DESC* pDesc, + UINT* pCount) { + Logger::err("D3D11VideoDevice::GetVideoDecoderConfigCount: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::GetVideoDecoderConfig( + const D3D11_VIDEO_DECODER_DESC* pDesc, + UINT Index, + D3D11_VIDEO_DECODER_CONFIG* pConfig) { + Logger::err("D3D11VideoDevice::GetVideoDecoderConfig: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::GetContentProtectionCaps( + const GUID* pCryptoType, + const GUID* pDecoderProfile, + D3D11_VIDEO_CONTENT_PROTECTION_CAPS* pCaps) { + Logger::err("D3D11VideoDevice::GetContentProtectionCaps: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CheckCryptoKeyExchange( + const GUID* pCryptoType, + const GUID* pDecoderProfile, + UINT Index, + GUID* pKeyExchangeType) { + Logger::err("D3D11VideoDevice::CheckCryptoKeyExchange: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::SetPrivateData( + REFGUID Name, + UINT DataSize, + const void* pData) { + return m_container->SetPrivateData(Name, DataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoDevice::SetPrivateDataInterface( + REFGUID Name, + const IUnknown* pData) { + return m_container->SetPrivateDataInterface(Name, pData); + } + + + + + WineDXGISwapChainFactory::WineDXGISwapChainFactory( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice) + : m_container(pContainer), m_device(pDevice) { + + } + + + ULONG STDMETHODCALLTYPE WineDXGISwapChainFactory::AddRef() { + return m_device->AddRef(); + } + + + ULONG STDMETHODCALLTYPE WineDXGISwapChainFactory::Release() { + return m_device->Release(); + } + + + HRESULT STDMETHODCALLTYPE WineDXGISwapChainFactory::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_device->QueryInterface(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE WineDXGISwapChainFactory::CreateSwapChainForHwnd( + IDXGIFactory* pFactory, + HWND hWnd, + const DXGI_SWAP_CHAIN_DESC1* pDesc, + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, + IDXGIOutput* pRestrictToOutput, + IDXGISwapChain1** ppSwapChain) { + InitReturnPtr(ppSwapChain); + + if (!ppSwapChain || !pDesc || !hWnd) + return DXGI_ERROR_INVALID_CALL; + + // Make sure the back buffer size is not zero + DXGI_SWAP_CHAIN_DESC1 desc = *pDesc; + + wsi::getWindowSize(hWnd, + desc.Width ? nullptr : &desc.Width, + desc.Height ? nullptr : &desc.Height); + + // If necessary, set up a default set of + // fullscreen parameters for the swap chain + DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsDesc; + + if (pFullscreenDesc) { + fsDesc = *pFullscreenDesc; + } else { + fsDesc.RefreshRate = { 0, 0 }; + fsDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + fsDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + fsDesc.Windowed = TRUE; + } + + try { + // Create presenter for the device + Com<D3D11SwapChain> presenter = new D3D11SwapChain( + m_container, m_device, hWnd, &desc); + + // Create the actual swap chain + *ppSwapChain = ref(new DxgiSwapChain( + pFactory, presenter.ptr(), hWnd, &desc, &fsDesc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + + + + DXGIDXVKDevice::DXGIDXVKDevice(D3D11DXGIDevice* pContainer) + : m_container(pContainer), m_apiVersion(11) { + + } + + + ULONG STDMETHODCALLTYPE DXGIDXVKDevice::AddRef() { + return m_container->AddRef(); + } + + + ULONG STDMETHODCALLTYPE DXGIDXVKDevice::Release() { + return m_container->Release(); + } + + + HRESULT STDMETHODCALLTYPE DXGIDXVKDevice::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_container->QueryInterface(riid, ppvObject); + } + + + void STDMETHODCALLTYPE DXGIDXVKDevice::SetAPIVersion( + UINT Version) { + m_apiVersion = Version; + } + + + UINT STDMETHODCALLTYPE DXGIDXVKDevice::GetAPIVersion() { + return m_apiVersion; + } + + + + + D3D11DXGIDevice::D3D11DXGIDevice( + IDXGIAdapter* pAdapter, + const Rc<DxvkInstance>& pDxvkInstance, + const Rc<DxvkAdapter>& pDxvkAdapter, + D3D_FEATURE_LEVEL FeatureLevel, + UINT FeatureFlags) + : m_dxgiAdapter (pAdapter), + m_dxvkInstance (pDxvkInstance), + m_dxvkAdapter (pDxvkAdapter), + m_dxvkDevice (CreateDevice(FeatureLevel)), + m_d3d11Device (this, FeatureLevel, FeatureFlags), + m_d3d11DeviceExt(this, &m_d3d11Device), + m_d3d11Interop (this, &m_d3d11Device), + m_d3d11Video (this, &m_d3d11Device), + m_metaDevice (this), + m_wineFactory (this, &m_d3d11Device) { + + } + + + D3D11DXGIDevice::~D3D11DXGIDevice() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(IDXGIObject) + || riid == __uuidof(IDXGIDevice) + || riid == __uuidof(IDXGIDevice1) + || riid == __uuidof(IDXGIDevice2) + || riid == __uuidof(IDXGIDevice3) + || riid == __uuidof(IDXGIDevice4)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(IDXGIVkInteropDevice) + || riid == __uuidof(IDXGIVkInteropDevice1)) { + *ppvObject = ref(&m_d3d11Interop); + return S_OK; + } + + if (riid == __uuidof(ID3D10Device) + || riid == __uuidof(ID3D10Device1)) { + *ppvObject = ref(m_d3d11Device.GetD3D10Interface()); + return S_OK; + } + + if (riid == __uuidof(ID3D11Device) + || riid == __uuidof(ID3D11Device1) + || riid == __uuidof(ID3D11Device2) + || riid == __uuidof(ID3D11Device3) + || riid == __uuidof(ID3D11Device4) + || riid == __uuidof(ID3D11Device5)) { + *ppvObject = ref(&m_d3d11Device); + return S_OK; + } + + if (riid == __uuidof(ID3D11VkExtDevice) + || riid == __uuidof(ID3D11VkExtDevice1)) { + *ppvObject = ref(&m_d3d11DeviceExt); + return S_OK; + } + + if (riid == __uuidof(IDXGIDXVKDevice)) { + *ppvObject = ref(&m_metaDevice); + return S_OK; + } + + if (riid == __uuidof(IWineDXGISwapChainFactory)) { + *ppvObject = ref(&m_wineFactory); + return S_OK; + } + + if (riid == __uuidof(ID3D11VideoDevice)) { + *ppvObject = ref(&m_d3d11Video); + return S_OK; + } + + if (riid == __uuidof(ID3D10Multithread)) { + Com<ID3D11DeviceContext> context; + m_d3d11Device.GetImmediateContext(&context); + return context->QueryInterface(riid, ppvObject); + } + + if (riid == __uuidof(ID3D11Debug)) + return E_NOINTERFACE; + + // Undocumented interfaces that are queried by some games + if (riid == GUID{0xd56e2a4c,0x5127,0x8437,{0x65,0x8a,0x98,0xc5,0xbb,0x78,0x94,0x98}}) + return E_NOINTERFACE; + + Logger::warn("D3D11DXGIDevice::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::GetParent( + REFIID riid, + void** ppParent) { + return m_dxgiAdapter->QueryInterface(riid, ppParent); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::CreateSurface( + const DXGI_SURFACE_DESC* pDesc, + UINT NumSurfaces, + DXGI_USAGE Usage, + const DXGI_SHARED_RESOURCE* pSharedResource, + IDXGISurface** ppSurface) { + if (!pDesc || (NumSurfaces && !ppSurface)) + return E_INVALIDARG; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = pDesc->Width; + desc.Height = pDesc->Height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = pDesc->Format; + desc.SampleDesc = pDesc->SampleDesc; + desc.BindFlags = 0; + desc.MiscFlags = 0; + + // Handle bind flags + if (Usage & DXGI_USAGE_RENDER_TARGET_OUTPUT) + desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + + if (Usage & DXGI_USAGE_SHADER_INPUT) + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + + if (Usage & DXGI_USAGE_UNORDERED_ACCESS) + desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + + // Handle CPU access flags + switch (Usage & DXGI_CPU_ACCESS_FIELD) { + case DXGI_CPU_ACCESS_NONE: + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + break; + + case DXGI_CPU_ACCESS_DYNAMIC: + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + break; + + case DXGI_CPU_ACCESS_READ_WRITE: + case DXGI_CPU_ACCESS_SCRATCH: + desc.Usage = D3D11_USAGE_STAGING; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + break; + + default: + return E_INVALIDARG; + } + + // Restrictions and limitations of CreateSurface are not + // well-documented, so we'll be a lenient on validation. + HRESULT hr = m_d3d11Device.CreateTexture2D(&desc, nullptr, nullptr); + + if (FAILED(hr)) + return hr; + + // We don't support shared resources + if (NumSurfaces && pSharedResource) + Logger::err("D3D11: CreateSurface: Shared surfaces not supported"); + + // Try to create the given number of surfaces + uint32_t surfacesCreated = 0; + hr = S_OK; + + for (uint32_t i = 0; i < NumSurfaces; i++) { + Com<ID3D11Texture2D> texture; + + hr = m_d3d11Device.CreateTexture2D(&desc, nullptr, &texture); + + if (SUCCEEDED(hr)) { + hr = texture->QueryInterface(__uuidof(IDXGISurface), + reinterpret_cast<void**>(&ppSurface[i])); + surfacesCreated = i + 1; + } + + if (FAILED(hr)) + break; + } + + // Don't leak surfaces if we failed to create one + if (FAILED(hr)) { + for (uint32_t i = 0; i < surfacesCreated; i++) + ppSurface[i]->Release(); + } + + return hr; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::GetAdapter( + IDXGIAdapter** pAdapter) { + if (pAdapter == nullptr) + return DXGI_ERROR_INVALID_CALL; + + *pAdapter = m_dxgiAdapter.ref(); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::GetGPUThreadPriority( + INT* pPriority) { + *pPriority = 0; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::QueryResourceResidency( + IUnknown* const* ppResources, + DXGI_RESIDENCY* pResidencyStatus, + UINT NumResources) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::err("D3D11DXGIDevice::QueryResourceResidency: Stub"); + + if (!ppResources || !pResidencyStatus) + return E_INVALIDARG; + + for (uint32_t i = 0; i < NumResources; i++) + pResidencyStatus[i] = DXGI_RESIDENCY_FULLY_RESIDENT; + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::SetGPUThreadPriority( + INT Priority) { + if (Priority < -7 || Priority > 7) + return E_INVALIDARG; + + Logger::err("DXGI: SetGPUThreadPriority: Ignoring"); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::GetMaximumFrameLatency( + UINT* pMaxLatency) { + if (!pMaxLatency) + return DXGI_ERROR_INVALID_CALL; + + *pMaxLatency = m_frameLatency; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::SetMaximumFrameLatency( + UINT MaxLatency) { + if (MaxLatency == 0) + MaxLatency = DefaultFrameLatency; + + if (MaxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS) + return DXGI_ERROR_INVALID_CALL; + + m_frameLatency = MaxLatency; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::OfferResources( + UINT NumResources, + IDXGIResource* const* ppResources, + DXGI_OFFER_RESOURCE_PRIORITY Priority) { + return OfferResources1(NumResources, ppResources, Priority, 0); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::OfferResources1( + UINT NumResources, + IDXGIResource* const* ppResources, + DXGI_OFFER_RESOURCE_PRIORITY Priority, + UINT Flags) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11DXGIDevice::OfferResources1: Stub"); + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::ReclaimResources( + UINT NumResources, + IDXGIResource* const* ppResources, + BOOL* pDiscarded) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11DXGIDevice::ReclaimResources: Stub"); + + if (pDiscarded) + *pDiscarded = false; + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::ReclaimResources1( + UINT NumResources, + IDXGIResource* const* ppResources, + DXGI_RECLAIM_RESOURCE_RESULTS* pResults) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11DXGIDevice::ReclaimResources1: Stub"); + + if (pResults) { + for (uint32_t i = 0; i < NumResources; i++) + pResults[i] = DXGI_RECLAIM_RESOURCE_RESULT_OK; + } + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::EnqueueSetEvent(HANDLE hEvent) { + Logger::err("D3D11DXGIDevice::EnqueueSetEvent: Not implemented"); + return DXGI_ERROR_UNSUPPORTED; + } + + + void STDMETHODCALLTYPE D3D11DXGIDevice::Trim() { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11DXGIDevice::Trim: Stub"); + } + + + Rc<DxvkDevice> STDMETHODCALLTYPE D3D11DXGIDevice::GetDXVKDevice() { + return m_dxvkDevice; + } + + + Rc<DxvkDevice> D3D11DXGIDevice::CreateDevice(D3D_FEATURE_LEVEL FeatureLevel) { + DxvkDeviceFeatures deviceFeatures = D3D11Device::GetDeviceFeatures(m_dxvkAdapter, FeatureLevel); + return m_dxvkAdapter->createDevice(m_dxvkInstance, deviceFeatures); + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.h new file mode 100644 index 00000000..7de5cf91 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.h @@ -0,0 +1,857 @@ +#pragma once + +#include <mutex> +#include <vector> + +#include "../dxbc/dxbc_options.h" + +#include "../dxgi/dxgi_object.h" +#include "../dxgi/dxgi_interfaces.h" + +#include "../dxvk/dxvk_cs.h" + +#include "../d3d10/d3d10_device.h" + +#include "../util/com/com_private_data.h" + +#include "d3d11_cmdlist.h" +#include "d3d11_cuda.h" +#include "d3d11_initializer.h" +#include "d3d11_interfaces.h" +#include "d3d11_interop.h" +#include "d3d11_options.h" +#include "d3d11_shader.h" +#include "d3d11_state.h" +#include "d3d11_util.h" + +namespace dxvk { + class DxgiAdapter; + + class D3D11Buffer; + class D3D11CommonShader; + class D3D11CommonTexture; + class D3D11Counter; + class D3D11DeviceContext; + class D3D11DXGIDevice; + class D3D11ImmediateContext; + class D3D11Predicate; + class D3D11Query; + class D3D11Texture1D; + class D3D11Texture2D; + class D3D11Texture3D; + + /** + * \brief D3D11 device implementation + * + * Implements the ID3D11Device interfaces + * as part of a \ref D3D11DeviceContainer. + */ + class D3D11Device final : public ID3D11Device5 { + /// Maximum number of resource init commands per command buffer + constexpr static uint64_t InitCommandThreshold = 50; + public: + + D3D11Device( + D3D11DXGIDevice* pContainer, + D3D_FEATURE_LEVEL FeatureLevel, + UINT FeatureFlags); + + ~D3D11Device(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE CreateBuffer( + const D3D11_BUFFER_DESC* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Buffer** ppBuffer); + + HRESULT STDMETHODCALLTYPE CreateTexture1D( + const D3D11_TEXTURE1D_DESC* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture1D** ppTexture1D); + + HRESULT STDMETHODCALLTYPE CreateTexture2D( + const D3D11_TEXTURE2D_DESC* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture2D** ppTexture2D); + + HRESULT STDMETHODCALLTYPE CreateTexture2D1( + const D3D11_TEXTURE2D_DESC1* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture2D1** ppTexture2D); + + HRESULT STDMETHODCALLTYPE CreateTexture3D( + const D3D11_TEXTURE3D_DESC* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture3D** ppTexture3D); + + HRESULT STDMETHODCALLTYPE CreateTexture3D1( + const D3D11_TEXTURE3D_DESC1* pDesc, + const D3D11_SUBRESOURCE_DATA* pInitialData, + ID3D11Texture3D1** ppTexture3D); + + HRESULT STDMETHODCALLTYPE CreateShaderResourceView( + ID3D11Resource* pResource, + const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, + ID3D11ShaderResourceView** ppSRView); + + HRESULT STDMETHODCALLTYPE CreateShaderResourceView1( + ID3D11Resource* pResource, + const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc, + ID3D11ShaderResourceView1** ppSRView); + + HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView( + ID3D11Resource* pResource, + const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, + ID3D11UnorderedAccessView** ppUAView); + + HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView1( + ID3D11Resource* pResource, + const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc, + ID3D11UnorderedAccessView1** ppUAView); + + HRESULT STDMETHODCALLTYPE CreateRenderTargetView( + ID3D11Resource* pResource, + const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, + ID3D11RenderTargetView** ppRTView); + + HRESULT STDMETHODCALLTYPE CreateRenderTargetView1( + ID3D11Resource* pResource, + const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc, + ID3D11RenderTargetView1** ppRTView); + + HRESULT STDMETHODCALLTYPE CreateDepthStencilView( + ID3D11Resource* pResource, + const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, + ID3D11DepthStencilView** ppDepthStencilView); + + HRESULT STDMETHODCALLTYPE CreateInputLayout( + const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, + UINT NumElements, + const void* pShaderBytecodeWithInputSignature, + SIZE_T BytecodeLength, + ID3D11InputLayout** ppInputLayout); + + HRESULT STDMETHODCALLTYPE CreateVertexShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11VertexShader** ppVertexShader); + + HRESULT STDMETHODCALLTYPE CreateGeometryShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11GeometryShader** ppGeometryShader); + + HRESULT STDMETHODCALLTYPE CreateGeometryShaderWithStreamOutput( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + const D3D11_SO_DECLARATION_ENTRY* pSODeclaration, + UINT NumEntries, + const UINT* pBufferStrides, + UINT NumStrides, + UINT RasterizedStream, + ID3D11ClassLinkage* pClassLinkage, + ID3D11GeometryShader** ppGeometryShader); + + HRESULT STDMETHODCALLTYPE CreatePixelShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11PixelShader** ppPixelShader); + + HRESULT STDMETHODCALLTYPE CreateHullShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11HullShader** ppHullShader); + + HRESULT STDMETHODCALLTYPE CreateDomainShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11DomainShader** ppDomainShader); + + HRESULT STDMETHODCALLTYPE CreateComputeShader( + const void* pShaderBytecode, + SIZE_T BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + ID3D11ComputeShader** ppComputeShader); + + HRESULT STDMETHODCALLTYPE CreateClassLinkage( + ID3D11ClassLinkage** ppLinkage); + + HRESULT STDMETHODCALLTYPE CreateBlendState( + const D3D11_BLEND_DESC* pBlendStateDesc, + ID3D11BlendState** ppBlendState); + + HRESULT STDMETHODCALLTYPE CreateBlendState1( + const D3D11_BLEND_DESC1* pBlendStateDesc, + ID3D11BlendState1** ppBlendState); + + HRESULT STDMETHODCALLTYPE CreateDepthStencilState( + const D3D11_DEPTH_STENCIL_DESC* pDepthStencilDesc, + ID3D11DepthStencilState** ppDepthStencilState); + + HRESULT STDMETHODCALLTYPE CreateRasterizerState( + const D3D11_RASTERIZER_DESC* pRasterizerDesc, + ID3D11RasterizerState** ppRasterizerState); + + HRESULT STDMETHODCALLTYPE CreateRasterizerState1( + const D3D11_RASTERIZER_DESC1* pRasterizerDesc, + ID3D11RasterizerState1** ppRasterizerState); + + HRESULT STDMETHODCALLTYPE CreateRasterizerState2( + const D3D11_RASTERIZER_DESC2* pRasterizerDesc, + ID3D11RasterizerState2** ppRasterizerState); + + HRESULT STDMETHODCALLTYPE CreateSamplerState( + const D3D11_SAMPLER_DESC* pSamplerDesc, + ID3D11SamplerState** ppSamplerState); + + HRESULT STDMETHODCALLTYPE CreateQuery( + const D3D11_QUERY_DESC* pQueryDesc, + ID3D11Query** ppQuery); + + HRESULT STDMETHODCALLTYPE CreateQuery1( + const D3D11_QUERY_DESC1* pQueryDesc, + ID3D11Query1** ppQuery); + + HRESULT STDMETHODCALLTYPE CreatePredicate( + const D3D11_QUERY_DESC* pPredicateDesc, + ID3D11Predicate** ppPredicate); + + HRESULT STDMETHODCALLTYPE CreateCounter( + const D3D11_COUNTER_DESC* pCounterDesc, + ID3D11Counter** ppCounter); + + HRESULT STDMETHODCALLTYPE CreateDeferredContext( + UINT ContextFlags, + ID3D11DeviceContext** ppDeferredContext); + + HRESULT STDMETHODCALLTYPE CreateDeferredContext1( + UINT ContextFlags, + ID3D11DeviceContext1** ppDeferredContext); + + HRESULT STDMETHODCALLTYPE CreateDeferredContext2( + UINT ContextFlags, + ID3D11DeviceContext2** ppDeferredContext); + + HRESULT STDMETHODCALLTYPE CreateDeferredContext3( + UINT ContextFlags, + ID3D11DeviceContext3** ppDeferredContext); + + HRESULT STDMETHODCALLTYPE CreateDeviceContextState( + UINT Flags, + const D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + REFIID EmulatedInterface, + D3D_FEATURE_LEVEL* pChosenFeatureLevel, + ID3DDeviceContextState** ppContextState); + + HRESULT STDMETHODCALLTYPE CreateFence( + UINT64 InitialValue, + D3D11_FENCE_FLAG Flags, + REFIID ReturnedInterface, + void** ppFence); + + void STDMETHODCALLTYPE ReadFromSubresource( + void* pDstData, + UINT DstRowPitch, + UINT DstDepthPitch, + ID3D11Resource* pSrcResource, + UINT SrcSubresource, + const D3D11_BOX* pSrcBox); + + void STDMETHODCALLTYPE WriteToSubresource( + ID3D11Resource* pDstResource, + UINT DstSubresource, + const D3D11_BOX* pDstBox, + const void* pSrcData, + UINT SrcRowPitch, + UINT SrcDepthPitch); + + HRESULT STDMETHODCALLTYPE OpenSharedResource( + HANDLE hResource, + REFIID ReturnedInterface, + void** ppResource); + + HRESULT STDMETHODCALLTYPE OpenSharedResource1( + HANDLE hResource, + REFIID returnedInterface, + void** ppResource); + + HRESULT STDMETHODCALLTYPE OpenSharedResourceByName( + LPCWSTR lpName, + DWORD dwDesiredAccess, + REFIID returnedInterface, + void** ppResource); + + HRESULT STDMETHODCALLTYPE OpenSharedFence( + HANDLE hFence, + REFIID ReturnedInterface, + void** ppFence); + + HRESULT STDMETHODCALLTYPE CheckFormatSupport( + DXGI_FORMAT Format, + UINT* pFormatSupport); + + HRESULT STDMETHODCALLTYPE CheckMultisampleQualityLevels( + DXGI_FORMAT Format, + UINT SampleCount, + UINT* pNumQualityLevels); + + HRESULT STDMETHODCALLTYPE CheckMultisampleQualityLevels1( + DXGI_FORMAT Format, + UINT SampleCount, + UINT Flags, + UINT* pNumQualityLevels); + + void STDMETHODCALLTYPE CheckCounterInfo( + D3D11_COUNTER_INFO* pCounterInfo); + + HRESULT STDMETHODCALLTYPE CheckCounter( + const D3D11_COUNTER_DESC* pDesc, + D3D11_COUNTER_TYPE* pType, + UINT* pActiveCounters, + LPSTR szName, + UINT* pNameLength, + LPSTR szUnits, + UINT* pUnitsLength, + LPSTR szDescription, + UINT* pDescriptionLength); + + HRESULT STDMETHODCALLTYPE CheckFeatureSupport( + D3D11_FEATURE Feature, + void* pFeatureSupportData, + UINT FeatureSupportDataSize); + + HRESULT STDMETHODCALLTYPE GetPrivateData( + REFGUID Name, + UINT *pDataSize, + void *pData); + + HRESULT STDMETHODCALLTYPE SetPrivateData( + REFGUID Name, + UINT DataSize, + const void *pData); + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + REFGUID Name, + const IUnknown *pUnknown); + + D3D_FEATURE_LEVEL STDMETHODCALLTYPE GetFeatureLevel(); + + UINT STDMETHODCALLTYPE GetCreationFlags(); + + HRESULT STDMETHODCALLTYPE GetDeviceRemovedReason(); + + void STDMETHODCALLTYPE GetImmediateContext( + ID3D11DeviceContext** ppImmediateContext); + + void STDMETHODCALLTYPE GetImmediateContext1( + ID3D11DeviceContext1** ppImmediateContext); + + void STDMETHODCALLTYPE GetImmediateContext2( + ID3D11DeviceContext2** ppImmediateContext); + + void STDMETHODCALLTYPE GetImmediateContext3( + ID3D11DeviceContext3** ppImmediateContext); + + HRESULT STDMETHODCALLTYPE SetExceptionMode(UINT RaiseFlags); + + UINT STDMETHODCALLTYPE GetExceptionMode(); + + void STDMETHODCALLTYPE GetResourceTiling( + ID3D11Resource* pTiledResource, + UINT* pNumTilesForEntireResource, + D3D11_PACKED_MIP_DESC* pPackedMipDesc, + D3D11_TILE_SHAPE* pStandardTileShapeForNonPackedMips, + UINT* pNumSubresourceTilings, + UINT FirstSubresourceTilingToGet, + D3D11_SUBRESOURCE_TILING* pSubresourceTilingsForNonPackedMips); + + HRESULT STDMETHODCALLTYPE RegisterDeviceRemovedEvent( + HANDLE hEvent, + DWORD* pdwCookie); + + void STDMETHODCALLTYPE UnregisterDeviceRemoved( + DWORD dwCookie); + + Rc<DxvkDevice> GetDXVKDevice() { + return m_dxvkDevice; + } + + void FlushInitContext(); + + VkPipelineStageFlags GetEnabledShaderStages() const { + return m_dxvkDevice->getShaderPipelineStages(); + } + + DXGI_VK_FORMAT_INFO LookupFormat( + DXGI_FORMAT Format, + DXGI_VK_FORMAT_MODE Mode) const; + + DXGI_VK_FORMAT_INFO LookupPackedFormat( + DXGI_FORMAT Format, + DXGI_VK_FORMAT_MODE Mode) const; + + DXGI_VK_FORMAT_FAMILY LookupFamily( + DXGI_FORMAT Format, + DXGI_VK_FORMAT_MODE Mode) const; + + DxvkCsChunkRef AllocCsChunk(DxvkCsChunkFlags flags) { + DxvkCsChunk* chunk = m_csChunkPool.allocChunk(flags); + return DxvkCsChunkRef(chunk, &m_csChunkPool); + } + + const D3D11Options* GetOptions() const { + return &m_d3d11Options; + } + + D3D10Device* GetD3D10Interface() const { + return m_d3d10Device; + } + + static bool CheckFeatureLevelSupport( + const Rc<DxvkInstance>& instance, + const Rc<DxvkAdapter>& adapter, + D3D_FEATURE_LEVEL featureLevel); + + static DxvkDeviceFeatures GetDeviceFeatures( + const Rc<DxvkAdapter>& adapter, + D3D_FEATURE_LEVEL featureLevel); + + private: + + IDXGIObject* m_container; + + D3D_FEATURE_LEVEL m_featureLevel; + UINT m_featureFlags; + + const Rc<DxvkDevice> m_dxvkDevice; + const Rc<DxvkAdapter> m_dxvkAdapter; + + const DXGIVkFormatTable m_d3d11Formats; + const D3D11Options m_d3d11Options; + const DxbcOptions m_dxbcOptions; + + DxvkCsChunkPool m_csChunkPool; + + D3D11Initializer* m_initializer = nullptr; + D3D10Device* m_d3d10Device = nullptr; + Com<D3D11ImmediateContext, false> m_context; + + D3D11StateObjectSet<D3D11BlendState> m_bsStateObjects; + D3D11StateObjectSet<D3D11DepthStencilState> m_dsStateObjects; + D3D11StateObjectSet<D3D11RasterizerState> m_rsStateObjects; + D3D11StateObjectSet<D3D11SamplerState> m_samplerObjects; + D3D11ShaderModuleSet m_shaderModules; + + HRESULT CreateShaderModule( + D3D11CommonShader* pShaderModule, + DxvkShaderKey ShaderKey, + const void* pShaderBytecode, + size_t BytecodeLength, + ID3D11ClassLinkage* pClassLinkage, + const DxbcModuleInfo* pModuleInfo); + + HRESULT GetFormatSupportFlags( + DXGI_FORMAT Format, + UINT* pFlags1, + UINT* pFlags2) const; + + BOOL GetImageTypeSupport( + VkFormat Format, + VkImageType Type) const; + + uint32_t GetViewPlaneIndex( + ID3D11Resource* pResource, + DXGI_FORMAT ViewFormat); + + template<typename Void> + void CopySubresourceData( + Void* pData, + UINT RowPitch, + UINT DepthPitch, + ID3D11Resource* pResource, + UINT Subresource, + const D3D11_BOX* pBox); + + static D3D_FEATURE_LEVEL GetMaxFeatureLevel( + const Rc<DxvkInstance>& pInstance); + + }; + + + /** + * \brief Extended D3D11 device + */ + class D3D11DeviceExt : public ID3D11VkExtDevice1 { + + public: + + D3D11DeviceExt( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + BOOL STDMETHODCALLTYPE GetExtensionSupport( + D3D11_VK_EXTENSION Extension); + + bool STDMETHODCALLTYPE GetCudaTextureObjectNVX( + uint32_t srvDriverHandle, + uint32_t samplerDriverHandle, + uint32_t* pCudaTextureHandle); + + bool STDMETHODCALLTYPE CreateCubinComputeShaderWithNameNVX( + const void* pCubin, + uint32_t size, + uint32_t blockX, + uint32_t blockY, + uint32_t blockZ, + const char* pShaderName, + IUnknown** phShader); + + bool STDMETHODCALLTYPE GetResourceHandleGPUVirtualAddressAndSizeNVX( + void* hObject, + uint64_t* gpuVAStart, + uint64_t* gpuVASize); + + bool STDMETHODCALLTYPE CreateUnorderedAccessViewAndGetDriverHandleNVX( + ID3D11Resource* pResource, + const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, + ID3D11UnorderedAccessView** ppUAV, + uint32_t* pDriverHandle); + + bool STDMETHODCALLTYPE CreateShaderResourceViewAndGetDriverHandleNVX( + ID3D11Resource* pResource, + const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, + ID3D11ShaderResourceView** ppSRV, + uint32_t* pDriverHandle); + + bool STDMETHODCALLTYPE CreateSamplerStateAndGetDriverHandleNVX( + const D3D11_SAMPLER_DESC* pSamplerDesc, + ID3D11SamplerState** ppSamplerState, + uint32_t* pDriverHandle); + + private: + + D3D11DXGIDevice* m_container; + D3D11Device* m_device; + + void AddSamplerAndHandleNVX( + ID3D11SamplerState* pSampler, + uint32_t Handle); + + ID3D11SamplerState* HandleToSamplerNVX( + uint32_t Handle); + + void AddSrvAndHandleNVX( + ID3D11ShaderResourceView* pSrv, + uint32_t Handle); + + ID3D11ShaderResourceView* HandleToSrvNVX( + uint32_t Handle); + + dxvk::mutex m_mapLock; + std::unordered_map<uint32_t, ID3D11SamplerState*> m_samplerHandleToPtr; + std::unordered_map<uint32_t, ID3D11ShaderResourceView*> m_srvHandleToPtr; + }; + + + /** + * \brief D3D11 video device + */ + class D3D11VideoDevice : public ID3D11VideoDevice { + + public: + + D3D11VideoDevice( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice); + + ~D3D11VideoDevice(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE CreateVideoDecoder( + const D3D11_VIDEO_DECODER_DESC* pVideoDesc, + const D3D11_VIDEO_DECODER_CONFIG* pConfig, + ID3D11VideoDecoder** ppDecoder); + + HRESULT STDMETHODCALLTYPE CreateVideoProcessor( + ID3D11VideoProcessorEnumerator* pEnum, + UINT RateConversionIndex, + ID3D11VideoProcessor** ppVideoProcessor); + + HRESULT STDMETHODCALLTYPE CreateAuthenticatedChannel( + D3D11_AUTHENTICATED_CHANNEL_TYPE ChannelType, + ID3D11AuthenticatedChannel** ppAuthenticatedChannel); + + HRESULT STDMETHODCALLTYPE CreateCryptoSession( + const GUID* pCryptoType, + const GUID* pDecoderProfile, + const GUID* pKeyExchangeType, + ID3D11CryptoSession** ppCryptoSession); + + HRESULT STDMETHODCALLTYPE CreateVideoDecoderOutputView( + ID3D11Resource* pResource, + const D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC* pDesc, + ID3D11VideoDecoderOutputView** ppVDOVView); + + HRESULT STDMETHODCALLTYPE CreateVideoProcessorInputView( + ID3D11Resource* pResource, + ID3D11VideoProcessorEnumerator* pEnum, + const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC* pDesc, + ID3D11VideoProcessorInputView** ppVPIView); + + HRESULT STDMETHODCALLTYPE CreateVideoProcessorOutputView( + ID3D11Resource* pResource, + ID3D11VideoProcessorEnumerator* pEnum, + const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc, + ID3D11VideoProcessorOutputView** ppVPOView); + + HRESULT STDMETHODCALLTYPE CreateVideoProcessorEnumerator( + const D3D11_VIDEO_PROCESSOR_CONTENT_DESC* pDesc, + ID3D11VideoProcessorEnumerator** ppEnum); + + UINT STDMETHODCALLTYPE GetVideoDecoderProfileCount(); + + HRESULT STDMETHODCALLTYPE GetVideoDecoderProfile( + UINT Index, + GUID* pDecoderProfile); + + HRESULT STDMETHODCALLTYPE CheckVideoDecoderFormat( + const GUID* pDecoderProfile, + DXGI_FORMAT Format, + BOOL* pSupported); + + HRESULT STDMETHODCALLTYPE GetVideoDecoderConfigCount( + const D3D11_VIDEO_DECODER_DESC* pDesc, + UINT* pCount); + + HRESULT STDMETHODCALLTYPE GetVideoDecoderConfig( + const D3D11_VIDEO_DECODER_DESC* pDesc, + UINT Index, + D3D11_VIDEO_DECODER_CONFIG* pConfig); + + HRESULT STDMETHODCALLTYPE GetContentProtectionCaps( + const GUID* pCryptoType, + const GUID* pDecoderProfile, + D3D11_VIDEO_CONTENT_PROTECTION_CAPS* pCaps); + + HRESULT STDMETHODCALLTYPE CheckCryptoKeyExchange( + const GUID* pCryptoType, + const GUID* pDecoderProfile, + UINT Index, + GUID* pKeyExchangeType); + + HRESULT STDMETHODCALLTYPE SetPrivateData( + REFGUID Name, + UINT DataSize, + const void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + REFGUID Name, + const IUnknown* pData); + + private: + + D3D11DXGIDevice* m_container; + D3D11Device* m_device; + + }; + + + /** + * \brief DXGI swap chain factory + */ + class WineDXGISwapChainFactory : public IWineDXGISwapChainFactory { + + public: + + WineDXGISwapChainFactory( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE CreateSwapChainForHwnd( + IDXGIFactory* pFactory, + HWND hWnd, + const DXGI_SWAP_CHAIN_DESC1* pDesc, + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, + IDXGIOutput* pRestrictToOutput, + IDXGISwapChain1** ppSwapChain); + + private: + + D3D11DXGIDevice* m_container; + D3D11Device* m_device; + + }; + + + /** + * \brief D3D11 device metadata shenanigans + */ + class DXGIDXVKDevice : public IDXGIDXVKDevice { + + public: + + DXGIDXVKDevice(D3D11DXGIDevice* pContainer); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void STDMETHODCALLTYPE SetAPIVersion( + UINT Version); + + UINT STDMETHODCALLTYPE GetAPIVersion(); + + private: + + D3D11DXGIDevice* m_container; + UINT m_apiVersion; + + }; + + + /** + * \brief D3D11 device container + * + * Stores all the objects that contribute to the D3D11 + * device implementation, including the DXGI device. + */ + class D3D11DXGIDevice : public DxgiObject<IDXGIDevice4> { + constexpr static uint32_t DefaultFrameLatency = 3; + public: + + D3D11DXGIDevice( + IDXGIAdapter* pAdapter, + const Rc<DxvkInstance>& pDxvkInstance, + const Rc<DxvkAdapter>& pDxvkAdapter, + D3D_FEATURE_LEVEL FeatureLevel, + UINT FeatureFlags); + + ~D3D11DXGIDevice(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE GetParent( + REFIID riid, + void** ppParent); + + HRESULT STDMETHODCALLTYPE CreateSurface( + const DXGI_SURFACE_DESC* pDesc, + UINT NumSurfaces, + DXGI_USAGE Usage, + const DXGI_SHARED_RESOURCE* pSharedResource, + IDXGISurface** ppSurface) final; + + HRESULT STDMETHODCALLTYPE GetAdapter( + IDXGIAdapter** pAdapter) final; + + HRESULT STDMETHODCALLTYPE GetGPUThreadPriority( + INT* pPriority) final; + + HRESULT STDMETHODCALLTYPE QueryResourceResidency( + IUnknown* const* ppResources, + DXGI_RESIDENCY* pResidencyStatus, + UINT NumResources) final; + + HRESULT STDMETHODCALLTYPE SetGPUThreadPriority( + INT Priority) final; + + HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency( + UINT* pMaxLatency) final; + + HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency( + UINT MaxLatency) final; + + HRESULT STDMETHODCALLTYPE OfferResources( + UINT NumResources, + IDXGIResource* const* ppResources, + DXGI_OFFER_RESOURCE_PRIORITY Priority) final; + + HRESULT STDMETHODCALLTYPE OfferResources1( + UINT NumResources, + IDXGIResource* const* ppResources, + DXGI_OFFER_RESOURCE_PRIORITY Priority, + UINT Flags) final; + + HRESULT STDMETHODCALLTYPE ReclaimResources( + UINT NumResources, + IDXGIResource* const* ppResources, + BOOL* pDiscarded) final; + + HRESULT STDMETHODCALLTYPE ReclaimResources1( + UINT NumResources, + IDXGIResource* const* ppResources, + DXGI_RECLAIM_RESOURCE_RESULTS* pResults) final; + + HRESULT STDMETHODCALLTYPE EnqueueSetEvent( + HANDLE hEvent) final; + + void STDMETHODCALLTYPE Trim() final; + + Rc<DxvkDevice> STDMETHODCALLTYPE GetDXVKDevice(); + + private: + + Com<IDXGIAdapter> m_dxgiAdapter; + + Rc<DxvkInstance> m_dxvkInstance; + Rc<DxvkAdapter> m_dxvkAdapter; + Rc<DxvkDevice> m_dxvkDevice; + + D3D11Device m_d3d11Device; + D3D11DeviceExt m_d3d11DeviceExt; + D3D11VkInterop m_d3d11Interop; + D3D11VideoDevice m_d3d11Video; + DXGIDXVKDevice m_metaDevice; + + WineDXGISwapChainFactory m_wineFactory; + + uint32_t m_frameLatency = DefaultFrameLatency; + + Rc<DxvkDevice> CreateDevice(D3D_FEATURE_LEVEL FeatureLevel); + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device_child.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device_child.h new file mode 100644 index 00000000..60eff07a --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device_child.h @@ -0,0 +1,130 @@ +#pragma once + +#include "d3d11_include.h" + +#include "../util/com/com_private_data.h" + +namespace dxvk { + + class D3D11Device; + + template<typename Base> + class D3D11DeviceObject : public Base { + + public: + + D3D11DeviceObject(D3D11Device* pDevice) + : m_parent(pDevice) { + + } + + HRESULT STDMETHODCALLTYPE GetPrivateData( + REFGUID guid, + UINT *pDataSize, + void *pData) final { + return m_privateData.getData( + guid, pDataSize, pData); + } + + HRESULT STDMETHODCALLTYPE SetPrivateData( + REFGUID guid, + UINT DataSize, + const void *pData) final { + return m_privateData.setData( + guid, DataSize, pData); + } + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + REFGUID guid, + const IUnknown *pUnknown) final { + return m_privateData.setInterface( + guid, pUnknown); + } + + void STDMETHODCALLTYPE GetDevice( + ID3D11Device** ppDevice) final { + *ppDevice = ref(GetParentInterface()); + } + + protected: + + ID3D11Device* GetParentInterface() const { + // We don't know the definition of ID3D11Device + // here, because D3D11Device includes this file. + return reinterpret_cast<ID3D11Device*>(m_parent); + } + + D3D11Device* const m_parent; + + private: + + ComPrivateData m_privateData; + + }; + + + template<typename Base> + class D3D11DeviceChild : public D3D11DeviceObject<ComObject<Base>> { + + public: + + D3D11DeviceChild(D3D11Device* pDevice) + : D3D11DeviceObject<ComObject<Base>>(pDevice) { + + } + + ULONG STDMETHODCALLTYPE AddRef() { + uint32_t refCount = this->m_refCount++; + if (unlikely(!refCount)) { + this->AddRefPrivate(); + this->GetParentInterface()->AddRef(); + } + + return refCount + 1; + } + + ULONG STDMETHODCALLTYPE Release() { + uint32_t refCount = --this->m_refCount; + if (unlikely(!refCount)) { + auto* parent = this->GetParentInterface(); + this->ReleasePrivate(); + parent->Release(); + } + return refCount; + } + + }; + + template<typename Base> + class D3D11StateObject : public D3D11DeviceObject<Base> { + + public: + + D3D11StateObject(D3D11Device* pDevice) + : D3D11DeviceObject<Base>(pDevice) { + + } + + ULONG STDMETHODCALLTYPE AddRef() { + uint32_t refCount = this->m_refCount++; + if (unlikely(!refCount)) + this->GetParentInterface()->AddRef(); + + return refCount + 1; + } + + ULONG STDMETHODCALLTYPE Release() { + uint32_t refCount = --this->m_refCount; + if (unlikely(!refCount)) + this->GetParentInterface()->Release(); + + return refCount; + } + + private: + + std::atomic<uint32_t> m_refCount = { 0u }; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.cpp new file mode 100644 index 00000000..0b9fc0f6 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.cpp @@ -0,0 +1,14 @@ +#include "d3d11_enums.h" + +std::ostream& operator << (std::ostream& os, D3D_FEATURE_LEVEL e) { + switch (e) { + ENUM_NAME(D3D_FEATURE_LEVEL_9_1); + ENUM_NAME(D3D_FEATURE_LEVEL_9_2); + ENUM_NAME(D3D_FEATURE_LEVEL_9_3); + ENUM_NAME(D3D_FEATURE_LEVEL_10_0); + ENUM_NAME(D3D_FEATURE_LEVEL_10_1); + ENUM_NAME(D3D_FEATURE_LEVEL_11_0); + ENUM_NAME(D3D_FEATURE_LEVEL_11_1); + ENUM_DEFAULT(e); + } +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.h new file mode 100644 index 00000000..d67d0cdd --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.h @@ -0,0 +1,7 @@ +#pragma once + +#include <ostream> + +#include "d3d11_include.h" + +std::ostream& operator << (std::ostream& os, D3D_FEATURE_LEVEL e);
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.cpp new file mode 100644 index 00000000..83e0618d --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.cpp @@ -0,0 +1,208 @@ +#include "d3d11_context.h" +#include "d3d11_device.h" +#include "d3d11_gdi.h" + +#ifndef DXVK_NATIVE +#include "../util/util_gdi.h" +#endif + +namespace dxvk { + + D3D11GDISurface::D3D11GDISurface( + ID3D11Resource* pResource, + UINT Subresource) + : m_resource (pResource), + m_subresource (Subresource), + m_readback (nullptr), + m_hdc (nullptr), + m_hbitmap (nullptr), + m_acquired (false) { + // Allocate memory for the bitmap + auto tex = GetCommonTexture(m_resource)->Desc(); + m_data.resize(tex->Width * tex->Height); + + // Create GDI DC + D3DKMT_CREATEDCFROMMEMORY desc; + desc.pMemory = m_data.data(); + desc.Format = D3DFMT_A8R8G8B8; + desc.Width = tex->Width; + desc.Height = tex->Height; + desc.Pitch = tex->Width * sizeof(uint32_t); + desc.hDeviceDc = CreateCompatibleDC(nullptr); + desc.pColorTable = nullptr; + desc.hDc = nullptr; + desc.hBitmap = nullptr; + + if (D3DKMTCreateDCFromMemory(&desc)) + Logger::err(str::format("D3D11: Failed to create GDI DC")); + + m_hdc = desc.hDc; + m_hbitmap = desc.hBitmap; + } + + + D3D11GDISurface::~D3D11GDISurface() { + if (m_readback) + m_readback->Release(); + + D3DKMT_DESTROYDCFROMMEMORY desc; + desc.hDC = m_hdc; + desc.hBitmap = m_hbitmap; + D3DKMTDestroyDCFromMemory(&desc); + } + + + HRESULT D3D11GDISurface::Acquire(BOOL Discard, HDC* phdc) { + if (!phdc) + return E_INVALIDARG; + + *phdc = nullptr; + + if (m_acquired) + return DXGI_ERROR_INVALID_CALL; + + if (!Discard) { + // Create a staging resource that we can map + if (!m_readback && FAILED(CreateReadbackResource())) { + Logger::err("D3D11: Failed to create GDI readback resource"); + return E_FAIL; + } + + // Copy subresource to staging image + Com<ID3D11Device> device; + Com<ID3D11DeviceContext> context; + + m_resource->GetDevice(&device); + device->GetImmediateContext(&context); + + context->CopySubresourceRegion(m_readback, 0, + 0, 0, 0, m_resource, m_subresource, nullptr); + + // Copy staging image to DC memory + auto tex = GetCommonTexture(m_resource)->Desc(); + auto rowData = reinterpret_cast<char*>(m_data.data()); + auto rowLength = sizeof(uint32_t) * tex->Width; + + D3D11_MAPPED_SUBRESOURCE sr; + context->Map(m_readback, 0, D3D11_MAP_READ, 0, &sr); + + for (uint32_t i = 0; i < tex->Height; i++) { + std::memcpy(rowData + rowLength * i, + reinterpret_cast<const char*>(sr.pData) + sr.RowPitch * i, + rowLength); + } + + context->Unmap(m_readback, 0); + } + + m_acquired = true; + *phdc = m_hdc; + return S_OK; + } + + + HRESULT D3D11GDISurface::Release(const RECT* pDirtyRect) { + if (!m_acquired) + return DXGI_ERROR_INVALID_CALL; + + Com<ID3D11Device> device; + Com<ID3D11DeviceContext> context; + + m_resource->GetDevice(&device); + device->GetImmediateContext(&context); + + // Commit changes made to the DC + auto tex = GetCommonTexture(m_resource)->Desc(); + + RECT rect; + + if (pDirtyRect) { + rect.left = std::max<LONG>(pDirtyRect->left, 0); + rect.top = std::max<LONG>(pDirtyRect->top, 0); + rect.right = std::min<LONG>(pDirtyRect->right, tex->Width); + rect.bottom = std::min<LONG>(pDirtyRect->bottom, tex->Height); + } else { + rect.left = 0; + rect.top = 0; + rect.right = tex->Width; + rect.bottom = tex->Height; + } + + if (rect.left < rect.right && rect.top < rect.bottom) { + D3D11_BOX box; + box.left = rect.left; + box.top = rect.top; + box.front = 0; + box.right = rect.right; + box.bottom = rect.bottom; + box.back = 1; + + context->UpdateSubresource(m_resource, m_subresource, + &box, m_data.data() + rect.left, + sizeof(uint32_t) * tex->Width, + sizeof(uint32_t) * tex->Width * tex->Height); + } + + m_acquired = false; + return S_OK; + } + + + HRESULT D3D11GDISurface::CreateReadbackResource() { + auto tex = GetCommonTexture(m_resource); + + Com<ID3D11Device> device; + Com<ID3D11DeviceContext> context; + + m_resource->GetDevice(&device); + device->GetImmediateContext(&context); + + D3D11_RESOURCE_DIMENSION dim = { }; + m_resource->GetType(&dim); + + VkImageSubresource sr = tex->GetSubresourceFromIndex( + VK_IMAGE_ASPECT_COLOR_BIT, m_subresource); + + switch (dim) { + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC desc; + desc.Width = std::max<UINT>(tex->Desc()->Width >> sr.mipLevel, 1); + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = tex->Desc()->Format; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + + ID3D11Texture1D* tex1D = nullptr; + HRESULT hr = device->CreateTexture1D(&desc, nullptr, &tex1D); + m_readback = tex1D; + return hr; + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC desc; + desc.Width = std::max<UINT>(tex->Desc()->Width >> sr.mipLevel, 1); + desc.Height = std::max<UINT>(tex->Desc()->Height >> sr.mipLevel, 1); + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = tex->Desc()->Format; + desc.SampleDesc= { 1, 0 }; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + + ID3D11Texture2D* tex2D = nullptr; + HRESULT hr = device->CreateTexture2D(&desc, nullptr, &tex2D); + m_readback = tex2D; + return hr; + } break; + + default: + return E_INVALIDARG; + } + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.h new file mode 100644 index 00000000..a2656c0a --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.h @@ -0,0 +1,41 @@ +#pragma once + +#include <vector> + +#include "d3d11_include.h" + +namespace dxvk { + + class D3D11GDISurface { + + public: + + D3D11GDISurface( + ID3D11Resource* pResource, + UINT Subresource); + + ~D3D11GDISurface(); + + HRESULT Acquire( + BOOL Discard, + HDC* phdc); + + HRESULT Release( + const RECT* pDirtyRect); + + private: + + ID3D11Resource* m_resource; + uint32_t m_subresource; + ID3D11Resource* m_readback; + HDC m_hdc; + HANDLE m_hbitmap; + bool m_acquired; + + std::vector<uint32_t> m_data; + + HRESULT CreateReadbackResource(); + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_include.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_include.h new file mode 100644 index 00000000..1598088a --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_include.h @@ -0,0 +1,46 @@ +#pragma once + +#include "../dxgi/dxgi_include.h" + +#include <d3d11_4.h> + +// This is not defined in the mingw headers +#ifndef D3D11_1_UAV_SLOT_COUNT +#define D3D11_1_UAV_SLOT_COUNT 64 +#endif + +#ifndef D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL +#define D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL 0xFFFFFFFF +#endif + +#ifndef D3D11_KEEP_UNORDERED_ACCESS_VIEWS +#define D3D11_KEEP_UNORDERED_ACCESS_VIEWS 0xFFFFFFFF +#endif + +#define D3D11_DXVK_USE_REMAINING_LAYERS 0xFFFFFFFF +#define D3D11_DXVK_USE_REMAINING_LEVELS 0xFFFFFFFF + +// Most of these were copied from d3d11.h +// For some strange reason, we cannot use the structures +// directly, although others from the same header work. +// Some structures are missing from the mingw headers. +#ifndef _MSC_VER +#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 9 +typedef enum D3D11_FORMAT_SUPPORT2 { + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_ADD = 0x1, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS = 0x2, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE = 0x4, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE = 0x8, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX = 0x10, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX = 0x20, + D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD = 0x40, + D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE = 0x80, + D3D11_FORMAT_SUPPORT2_OUTPUT_MERGER_LOGIC_OP = 0x100, + D3D11_FORMAT_SUPPORT2_TILED = 0x200, + D3D11_FORMAT_SUPPORT2_SHAREABLE = 0x400, + D3D11_FORMAT_SUPPORT2_MULTIPLANE_OVERLAY = 0x4000 +} D3D11_FORMAT_SUPPORT2; +#define D3D11_RESOURCE_MISC_TILE_POOL (0x20000) +#define D3D11_RESOURCE_MISC_TILED (0x40000) +#endif // !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 9 +#endif // _MSC_VER diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.cpp new file mode 100644 index 00000000..d1d66f19 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.cpp @@ -0,0 +1,290 @@ +#include <cstring> + +#include "d3d11_device.h" +#include "d3d11_initializer.h" + +namespace dxvk { + + D3D11Initializer::D3D11Initializer( + D3D11Device* pParent) + : m_parent(pParent), + m_device(pParent->GetDXVKDevice()), + m_context(m_device->createContext()) { + m_context->beginRecording( + m_device->createCommandList()); + } + + + D3D11Initializer::~D3D11Initializer() { + + } + + + void D3D11Initializer::Flush() { + std::lock_guard<dxvk::mutex> lock(m_mutex); + + if (m_transferCommands != 0) + FlushInternal(); + } + + void D3D11Initializer::InitBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + VkMemoryPropertyFlags memFlags = pBuffer->GetBuffer()->memFlags(); + + (memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + ? InitHostVisibleBuffer(pBuffer, pInitialData) + : InitDeviceLocalBuffer(pBuffer, pInitialData); + } + + + void D3D11Initializer::InitTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + (pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) + ? InitHostVisibleTexture(pTexture, pInitialData) + : InitDeviceLocalTexture(pTexture, pInitialData); + } + + + void D3D11Initializer::InitUavCounter( + D3D11UnorderedAccessView* pUav) { + auto counterBuffer = pUav->GetCounterSlice(); + + if (!counterBuffer.defined()) + return; + + std::lock_guard<dxvk::mutex> lock(m_mutex); + m_transferCommands += 1; + + const uint32_t zero = 0; + m_context->updateBuffer( + counterBuffer.buffer(), + 0, sizeof(zero), &zero); + + FlushImplicit(); + } + + + void D3D11Initializer::InitDeviceLocalBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + std::lock_guard<dxvk::mutex> lock(m_mutex); + + DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice(); + + if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { + m_transferMemory += bufferSlice.length(); + m_transferCommands += 1; + + m_context->uploadBuffer( + bufferSlice.buffer(), + pInitialData->pSysMem); + } else { + m_transferCommands += 1; + + m_context->clearBuffer( + bufferSlice.buffer(), + bufferSlice.offset(), + bufferSlice.length(), + 0u); + } + + FlushImplicit(); + } + + + void D3D11Initializer::InitHostVisibleBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + // If the buffer is mapped, we can write data directly + // to the mapped memory region instead of doing it on + // the GPU. Same goes for zero-initialization. + DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice(); + + if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { + std::memcpy( + bufferSlice.mapPtr(0), + pInitialData->pSysMem, + bufferSlice.length()); + } else { + std::memset( + bufferSlice.mapPtr(0), 0, + bufferSlice.length()); + } + } + + + void D3D11Initializer::InitDeviceLocalTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + std::lock_guard<dxvk::mutex> lock(m_mutex); + + Rc<DxvkImage> image = pTexture->GetImage(); + + auto mapMode = pTexture->GetMapMode(); + auto desc = pTexture->Desc(); + + VkFormat packedFormat = m_parent->LookupPackedFormat(desc->Format, pTexture->GetFormatMode()).Format; + auto formatInfo = imageFormatInfo(packedFormat); + + if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { + // pInitialData is an array that stores an entry for + // every single subresource. Since we will define all + // subresources, this counts as initialization. + for (uint32_t layer = 0; layer < desc->ArraySize; layer++) { + for (uint32_t level = 0; level < desc->MipLevels; level++) { + const uint32_t id = D3D11CalcSubresource( + level, layer, desc->MipLevels); + + VkOffset3D mipLevelOffset = { 0, 0, 0 }; + VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(level); + + if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) { + m_transferCommands += 1; + m_transferMemory += pTexture->GetSubresourceLayout(formatInfo->aspectMask, id).Size; + + VkImageSubresourceLayers subresourceLayers; + subresourceLayers.aspectMask = formatInfo->aspectMask; + subresourceLayers.mipLevel = level; + subresourceLayers.baseArrayLayer = layer; + subresourceLayers.layerCount = 1; + + if (formatInfo->aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + m_context->uploadImage( + image, subresourceLayers, + pInitialData[id].pSysMem, + pInitialData[id].SysMemPitch, + pInitialData[id].SysMemSlicePitch); + } else { + m_context->updateDepthStencilImage( + image, subresourceLayers, + VkOffset2D { mipLevelOffset.x, mipLevelOffset.y }, + VkExtent2D { mipLevelExtent.width, mipLevelExtent.height }, + pInitialData[id].pSysMem, + pInitialData[id].SysMemPitch, + pInitialData[id].SysMemSlicePitch, + packedFormat); + } + } + + if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) { + util::packImageData(pTexture->GetMappedBuffer(id)->mapPtr(0), + pInitialData[id].pSysMem, pInitialData[id].SysMemPitch, pInitialData[id].SysMemSlicePitch, + 0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask); + } + } + } + } else { + if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) { + m_transferCommands += 1; + + // While the Microsoft docs state that resource contents are + // undefined if no initial data is provided, some applications + // expect a resource to be pre-cleared. We can only do that + // for non-compressed images, but that should be fine. + VkImageSubresourceRange subresources; + subresources.aspectMask = formatInfo->aspectMask; + subresources.baseMipLevel = 0; + subresources.levelCount = desc->MipLevels; + subresources.baseArrayLayer = 0; + subresources.layerCount = desc->ArraySize; + + if (formatInfo->flags.any(DxvkFormatFlag::BlockCompressed, DxvkFormatFlag::MultiPlane)) { + m_context->clearCompressedColorImage(image, subresources); + } else { + if (subresources.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { + VkClearColorValue value = { }; + + m_context->clearColorImage( + image, value, subresources); + } else { + VkClearDepthStencilValue value; + value.depth = 0.0f; + value.stencil = 0; + + m_context->clearDepthStencilImage( + image, value, subresources); + } + } + } + + if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) { + for (uint32_t i = 0; i < pTexture->CountSubresources(); i++) { + auto buffer = pTexture->GetMappedBuffer(i); + std::memset(buffer->mapPtr(0), 0, buffer->info().size); + } + } + } + + FlushImplicit(); + } + + + void D3D11Initializer::InitHostVisibleTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + Rc<DxvkImage> image = pTexture->GetImage(); + + for (uint32_t layer = 0; layer < image->info().numLayers; layer++) { + for (uint32_t level = 0; level < image->info().mipLevels; level++) { + VkImageSubresource subresource; + subresource.aspectMask = image->formatInfo()->aspectMask; + subresource.mipLevel = level; + subresource.arrayLayer = layer; + + VkExtent3D blockCount = util::computeBlockCount( + image->mipLevelExtent(level), + image->formatInfo()->blockSize); + + VkSubresourceLayout layout = image->querySubresourceLayout(subresource); + + auto initialData = pInitialData + ? &pInitialData[D3D11CalcSubresource(level, layer, image->info().mipLevels)] + : nullptr; + + for (uint32_t z = 0; z < blockCount.depth; z++) { + for (uint32_t y = 0; y < blockCount.height; y++) { + auto size = blockCount.width * image->formatInfo()->elementSize; + auto dst = image->mapPtr(layout.offset + y * layout.rowPitch + z * layout.depthPitch); + + if (initialData) { + auto src = reinterpret_cast<const char*>(initialData->pSysMem) + + y * initialData->SysMemPitch + + z * initialData->SysMemSlicePitch; + std::memcpy(dst, src, size); + } else { + std::memset(dst, 0, size); + } + } + } + } + } + + // Initialize the image on the GPU + std::lock_guard<dxvk::mutex> lock(m_mutex); + + VkImageSubresourceRange subresources = image->getAvailableSubresources(); + + m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_PREINITIALIZED); + + m_transferCommands += 1; + FlushImplicit(); + } + + + void D3D11Initializer::FlushImplicit() { + if (m_transferCommands > MaxTransferCommands + || m_transferMemory > MaxTransferMemory) + FlushInternal(); + } + + + void D3D11Initializer::FlushInternal() { + m_context->flushCommandList(); + + m_transferCommands = 0; + m_transferMemory = 0; + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.h new file mode 100644 index 00000000..8c96babd --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.h @@ -0,0 +1,73 @@ +#pragma once + +#include "d3d11_buffer.h" +#include "d3d11_texture.h" + +namespace dxvk { + + class D3D11Device; + + /** + * \brief Resource initialization context + * + * Manages a context which is used for resource + * initialization. This includes initialization + * with application-defined data, as well as + * zero-initialization for buffers and images. + */ + class D3D11Initializer { + constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024; + constexpr static size_t MaxTransferCommands = 512; + public: + + D3D11Initializer( + D3D11Device* pParent); + + ~D3D11Initializer(); + + void Flush(); + + void InitBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitUavCounter( + D3D11UnorderedAccessView* pUav); + + private: + + dxvk::mutex m_mutex; + + D3D11Device* m_parent; + Rc<DxvkDevice> m_device; + Rc<DxvkContext> m_context; + + size_t m_transferCommands = 0; + size_t m_transferMemory = 0; + + void InitDeviceLocalBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitHostVisibleBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitDeviceLocalTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitHostVisibleTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void FlushImplicit(); + void FlushInternal(); + + }; + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.cpp new file mode 100644 index 00000000..abf3d125 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.cpp @@ -0,0 +1,84 @@ +#include "d3d11_device.h" +#include "d3d11_input_layout.h" + +namespace dxvk { + + D3D11InputLayout::D3D11InputLayout( + D3D11Device* pDevice, + uint32_t numAttributes, + const DxvkVertexAttribute* pAttributes, + uint32_t numBindings, + const DxvkVertexBinding* pBindings) + : D3D11DeviceChild<ID3D11InputLayout>(pDevice), + m_d3d10(this) { + m_attributes.resize(numAttributes); + m_bindings.resize(numBindings); + + for (uint32_t i = 0; i < numAttributes; i++) + m_attributes.at(i) = pAttributes[i]; + + for (uint32_t i = 0; i < numBindings; i++) + m_bindings.at(i) = pBindings[i]; + } + + + D3D11InputLayout::~D3D11InputLayout() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11InputLayout::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11InputLayout)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10InputLayout)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + Logger::warn("D3D11InputLayout::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void D3D11InputLayout::BindToContext(const Rc<DxvkContext>& ctx) { + ctx->setInputLayout( + m_attributes.size(), + m_attributes.data(), + m_bindings.size(), + m_bindings.data()); + } + + + bool D3D11InputLayout::Compare(const D3D11InputLayout* pOther) const { + bool eq = m_attributes.size() == pOther->m_attributes.size() + && m_bindings.size() == pOther->m_bindings.size(); + + for (uint32_t i = 0; eq && i < m_attributes.size(); i++) { + eq &= m_attributes[i].location == pOther->m_attributes[i].location + && m_attributes[i].binding == pOther->m_attributes[i].binding + && m_attributes[i].format == pOther->m_attributes[i].format + && m_attributes[i].offset == pOther->m_attributes[i].offset; + } + + for (uint32_t i = 0; eq && i < m_bindings.size(); i++) { + eq &= m_bindings[i].binding == pOther->m_bindings[i].binding + && m_bindings[i].fetchRate == pOther->m_bindings[i].fetchRate + && m_bindings[i].inputRate == pOther->m_bindings[i].inputRate; + } + + return eq; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.h new file mode 100644 index 00000000..8e472e2e --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.h @@ -0,0 +1,47 @@ +#pragma once + +#include "d3d11_device_child.h" + +#include "../d3d10/d3d10_input_layout.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11InputLayout : public D3D11DeviceChild<ID3D11InputLayout> { + + public: + + D3D11InputLayout( + D3D11Device* pDevice, + uint32_t numAttributes, + const DxvkVertexAttribute* pAttributes, + uint32_t numBindings, + const DxvkVertexBinding* pBindings); + + ~D3D11InputLayout(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void BindToContext( + const Rc<DxvkContext>& ctx); + + bool Compare( + const D3D11InputLayout* pOther) const; + + D3D10InputLayout* GetD3D10Iface() { + return &m_d3d10; + } + + private: + + std::vector<DxvkVertexAttribute> m_attributes; + std::vector<DxvkVertexBinding> m_bindings; + + D3D10InputLayout m_d3d10; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interfaces.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interfaces.h new file mode 100644 index 00000000..3b0629bb --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interfaces.h @@ -0,0 +1,176 @@ +#pragma once + +#include "../dxgi/dxgi_interfaces.h" + +#include "d3d11_include.h" + +/** + * \brief D3D11 extension + * + * Lists D3D11 extensions supported by DXVK. + */ +enum D3D11_VK_EXTENSION : uint32_t { + D3D11_VK_EXT_MULTI_DRAW_INDIRECT = 0, + D3D11_VK_EXT_MULTI_DRAW_INDIRECT_COUNT = 1, + D3D11_VK_EXT_DEPTH_BOUNDS = 2, + D3D11_VK_EXT_BARRIER_CONTROL = 3, + D3D11_VK_NVX_BINARY_IMPORT = 4, + D3D11_VK_NVX_IMAGE_VIEW_HANDLE = 5, +}; + + +/** + * \brief Barrier control flags + */ +enum D3D11_VK_BARRIER_CONTROL : uint32_t { + D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE = 1 << 0, + D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1, +}; + + +/** + * \brief Extended D3D11 device + * + * Introduces a method to check for extension support. + */ +MIDL_INTERFACE("8a6e3c42-f74c-45b7-8265-a231b677ca17") +ID3D11VkExtDevice : public IUnknown { + /** + * \brief Checks whether an extension is supported + * + * \param [in] Extension The extension to check + * \returns \c TRUE if the extension is supported + */ + virtual BOOL STDMETHODCALLTYPE GetExtensionSupport( + D3D11_VK_EXTENSION Extension) = 0; + +}; + + +/** + * \brief Extended extended D3D11 device + * + * Introduces methods to get virtual addresses and driver + * handles for resources, and create and destroy objects + * for D3D11-Cuda interop. + */ +MIDL_INTERFACE("cfcf64ef-9586-46d0-bca4-97cf2ca61b06") +ID3D11VkExtDevice1 : public ID3D11VkExtDevice { + + virtual bool STDMETHODCALLTYPE GetResourceHandleGPUVirtualAddressAndSizeNVX( + void* hObject, + uint64_t* gpuVAStart, + uint64_t* gpuVASize) = 0; + + virtual bool STDMETHODCALLTYPE CreateUnorderedAccessViewAndGetDriverHandleNVX( + ID3D11Resource* pResource, + const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, + ID3D11UnorderedAccessView** ppUAV, + uint32_t* pDriverHandle) = 0; + + virtual bool STDMETHODCALLTYPE CreateShaderResourceViewAndGetDriverHandleNVX( + ID3D11Resource* pResource, + const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, + ID3D11ShaderResourceView** ppSRV, + uint32_t* pDriverHandle) = 0; + + virtual bool STDMETHODCALLTYPE CreateSamplerStateAndGetDriverHandleNVX( + const D3D11_SAMPLER_DESC* pSamplerDesc, + ID3D11SamplerState** ppSamplerState, + uint32_t* pDriverHandle) = 0; + + virtual bool STDMETHODCALLTYPE CreateCubinComputeShaderWithNameNVX( + const void* pCubin, + uint32_t size, + uint32_t blockX, + uint32_t blockY, + uint32_t blockZ, + const char* pShaderName, + IUnknown** phShader) = 0; + + virtual bool STDMETHODCALLTYPE GetCudaTextureObjectNVX( + uint32_t srvDriverHandle, + uint32_t samplerDriverHandle, + uint32_t* pCudaTextureHandle) = 0; +}; + + +/** + * \brief Extended D3D11 context + * + * Provides functionality for various D3D11 + * extensions. + */ +MIDL_INTERFACE("fd0bca13-5cb6-4c3a-987e-4750de2ca791") +ID3D11VkExtContext : public IUnknown { + virtual void STDMETHODCALLTYPE MultiDrawIndirect( + UINT DrawCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs) = 0; + + virtual void STDMETHODCALLTYPE MultiDrawIndexedIndirect( + UINT DrawCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs) = 0; + + virtual void STDMETHODCALLTYPE MultiDrawIndirectCount( + UINT MaxDrawCount, + ID3D11Buffer* pBufferForCount, + UINT ByteOffsetForCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs) = 0; + + virtual void STDMETHODCALLTYPE MultiDrawIndexedIndirectCount( + UINT MaxDrawCount, + ID3D11Buffer* pBufferForCount, + UINT ByteOffsetForCount, + ID3D11Buffer* pBufferForArgs, + UINT ByteOffsetForArgs, + UINT ByteStrideForArgs) = 0; + + virtual void STDMETHODCALLTYPE SetDepthBoundsTest( + BOOL Enable, + FLOAT MinDepthBounds, + FLOAT MaxDepthBounds) = 0; + + virtual void STDMETHODCALLTYPE SetBarrierControl( + UINT ControlFlags) = 0; +}; + + +/** + * \brief Extended extended D3D11 context + * + * Provides functionality to launch a Cuda kernel + */ +MIDL_INTERFACE("874b09b2-ae0b-41d8-8476-5f3b7a0e879d") +ID3D11VkExtContext1 : public ID3D11VkExtContext { + + virtual bool STDMETHODCALLTYPE LaunchCubinShaderNVX( + IUnknown* hShader, + uint32_t gridX, + uint32_t gridY, + uint32_t gridZ, + const void* pParams, + uint32_t paramSize, + void* const* pReadResources, + uint32_t numReadResources, + void* const* pWriteResources, + uint32_t numWriteResources) = 0; +}; + + +#ifdef _MSC_VER +struct __declspec(uuid("8a6e3c42-f74c-45b7-8265-a231b677ca17")) ID3D11VkExtDevice; +struct __declspec(uuid("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")) ID3D11VkExtDevice1; +struct __declspec(uuid("fd0bca13-5cb6-4c3a-987e-4750de2ca791")) ID3D11VkExtContext; +struct __declspec(uuid("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")) ID3D11VkExtContext1; +#else +__CRT_UUID_DECL(ID3D11VkExtDevice, 0x8a6e3c42,0xf74c,0x45b7,0x82,0x65,0xa2,0x31,0xb6,0x77,0xca,0x17); +__CRT_UUID_DECL(ID3D11VkExtDevice1, 0xcfcf64ef,0x9586,0x46d0,0xbc,0xa4,0x97,0xcf,0x2c,0xa6,0x1b,0x06); +__CRT_UUID_DECL(ID3D11VkExtContext, 0xfd0bca13,0x5cb6,0x4c3a,0x98,0x7e,0x47,0x50,0xde,0x2c,0xa7,0x91); +__CRT_UUID_DECL(ID3D11VkExtContext1, 0x874b09b2,0xae0b,0x41d8,0x84,0x76,0x5f,0x3b,0x7a,0x0e,0x87,0x9d); +#endif diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.cpp new file mode 100644 index 00000000..9584b6ab --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.cpp @@ -0,0 +1,166 @@ +#include "d3d11_context_imm.h" +#include "d3d11_interop.h" +#include "d3d11_device.h" + +#include "../dxvk/dxvk_adapter.h" +#include "../dxvk/dxvk_device.h" +#include "../dxvk/dxvk_instance.h" + +namespace dxvk { + + D3D11VkInterop::D3D11VkInterop( + IDXGIObject* pContainer, + D3D11Device* pDevice) + : m_container (pContainer), + m_device (pDevice) { } + + + D3D11VkInterop::~D3D11VkInterop() { + + } + + + ULONG STDMETHODCALLTYPE D3D11VkInterop::AddRef() { + return m_container->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11VkInterop::Release() { + return m_container->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11VkInterop::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_container->QueryInterface(riid, ppvObject); + } + + + void STDMETHODCALLTYPE D3D11VkInterop::GetVulkanHandles( + VkInstance* pInstance, + VkPhysicalDevice* pPhysDev, + VkDevice* pDevice) { + auto device = m_device->GetDXVKDevice(); + auto adapter = device->adapter(); + auto instance = device->instance(); + + if (pDevice != nullptr) + *pDevice = device->handle(); + + if (pPhysDev != nullptr) + *pPhysDev = adapter->handle(); + + if (pInstance != nullptr) + *pInstance = instance->handle(); + } + + + void STDMETHODCALLTYPE D3D11VkInterop::GetSubmissionQueue( + VkQueue* pQueue, + uint32_t* pQueueFamilyIndex) { + auto device = static_cast<D3D11Device*>(m_device)->GetDXVKDevice(); + DxvkDeviceQueue queue = device->queues().graphics; + + if (pQueue != nullptr) + *pQueue = queue.queueHandle; + + if (pQueueFamilyIndex != nullptr) + *pQueueFamilyIndex = queue.queueFamily; + } + + + void STDMETHODCALLTYPE D3D11VkInterop::TransitionSurfaceLayout( + IDXGIVkInteropSurface* pSurface, + const VkImageSubresourceRange* pSubresources, + VkImageLayout OldLayout, + VkImageLayout NewLayout) { + Com<ID3D11DeviceContext> deviceContext = nullptr; + m_device->GetImmediateContext(&deviceContext); + + auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr()); + + immediateContext->TransitionSurfaceLayout( + pSurface, pSubresources, OldLayout, NewLayout); + } + + + void STDMETHODCALLTYPE D3D11VkInterop::FlushRenderingCommands() { + Com<ID3D11DeviceContext> deviceContext = nullptr; + m_device->GetImmediateContext(&deviceContext); + + auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr()); + immediateContext->Flush(); + immediateContext->SynchronizeCsThread(); + } + + + void STDMETHODCALLTYPE D3D11VkInterop::LockSubmissionQueue() { + m_device->GetDXVKDevice()->lockSubmission(); + } + + + void STDMETHODCALLTYPE D3D11VkInterop::ReleaseSubmissionQueue() { + m_device->GetDXVKDevice()->unlockSubmission(); + } + + + void STDMETHODCALLTYPE D3D11VkInterop::GetSubmissionQueue1( + VkQueue* pQueue, + uint32_t* pQueueIndex, + uint32_t* pQueueFamilyIndex) { + auto device = static_cast<D3D11Device*>(m_device)->GetDXVKDevice(); + DxvkDeviceQueue queue = device->queues().graphics; + + if (pQueue != nullptr) + *pQueue = queue.queueHandle; + + if (pQueueIndex != nullptr) + *pQueueIndex = queue.queueIndex; + + if (pQueueFamilyIndex != nullptr) + *pQueueFamilyIndex = queue.queueFamily; + } + + HRESULT STDMETHODCALLTYPE D3D11VkInterop::CreateTexture2DFromVkImage( + const D3D11_TEXTURE2D_DESC1 *pDesc, + VkImage vkImage, + ID3D11Texture2D **ppTexture2D) { + + InitReturnPtr(ppTexture2D); + + if (!pDesc) + return E_INVALIDARG; + + D3D11_COMMON_TEXTURE_DESC desc; + desc.Width = pDesc->Width; + desc.Height = pDesc->Height; + desc.Depth = 1; + desc.MipLevels = pDesc->MipLevels; + desc.ArraySize = pDesc->ArraySize; + desc.Format = pDesc->Format; + desc.SampleDesc = pDesc->SampleDesc; + desc.Usage = pDesc->Usage; + desc.BindFlags = pDesc->BindFlags; + desc.CPUAccessFlags = pDesc->CPUAccessFlags; + desc.MiscFlags = pDesc->MiscFlags; + desc.TextureLayout = pDesc->TextureLayout; + + HRESULT hr = D3D11CommonTexture::NormalizeTextureProperties(&desc); + + if (FAILED(hr)) + return hr; + + if (!ppTexture2D) + return S_FALSE; + + try { + Com<D3D11Texture2D> texture = new D3D11Texture2D(m_device, &desc, 0, vkImage); + *ppTexture2D = texture.ref(); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.h new file mode 100644 index 00000000..48ee4c3b --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.h @@ -0,0 +1,67 @@ +#pragma once + +#include "../dxgi/dxgi_interfaces.h" + +#include "d3d11_include.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11VkInterop : public ComObject<IDXGIVkInteropDevice1> { + + public: + + D3D11VkInterop( + IDXGIObject* pContainer, + D3D11Device* pDevice); + + ~D3D11VkInterop(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void STDMETHODCALLTYPE GetVulkanHandles( + VkInstance* pInstance, + VkPhysicalDevice* pPhysDev, + VkDevice* pDevice); + + void STDMETHODCALLTYPE GetSubmissionQueue( + VkQueue* pQueue, + uint32_t* pQueueFamilyIndex); + + void STDMETHODCALLTYPE TransitionSurfaceLayout( + IDXGIVkInteropSurface* pSurface, + const VkImageSubresourceRange* pSubresources, + VkImageLayout OldLayout, + VkImageLayout NewLayout); + + void STDMETHODCALLTYPE FlushRenderingCommands(); + + void STDMETHODCALLTYPE LockSubmissionQueue(); + + void STDMETHODCALLTYPE ReleaseSubmissionQueue(); + + void STDMETHODCALLTYPE GetSubmissionQueue1( + VkQueue* pQueue, + uint32_t* pQueueIndex, + uint32_t* pQueueFamilyIndex); + + HRESULT STDMETHODCALLTYPE CreateTexture2DFromVkImage( + const D3D11_TEXTURE2D_DESC1* pDesc, + VkImage vkImage, + ID3D11Texture2D** ppTexture2D); + + private: + + IDXGIObject* m_container; + D3D11Device* m_device; + + }; + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_main.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_main.cpp new file mode 100644 index 00000000..c0be5283 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_main.cpp @@ -0,0 +1,247 @@ +#include <array> + +#include "../dxgi/dxgi_adapter.h" + +#include "../dxvk/dxvk_instance.h" + +#include "d3d11_device.h" +#include "d3d11_enums.h" +#include "d3d11_interop.h" + +namespace dxvk { +#ifndef VBOX + Logger Logger::s_instance("d3d11.log"); +#endif +} + +extern "C" { + using namespace dxvk; + + DLLEXPORT HRESULT __stdcall D3D11CoreCreateDevice( + IDXGIFactory* pFactory, + IDXGIAdapter* pAdapter, + UINT Flags, + const D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + ID3D11Device** ppDevice) { + InitReturnPtr(ppDevice); + + Rc<DxvkAdapter> dxvkAdapter; + Rc<DxvkInstance> dxvkInstance; + + Com<IDXGIDXVKAdapter> dxgiVkAdapter; + + // Try to find the corresponding Vulkan device for the DXGI adapter + if (SUCCEEDED(pAdapter->QueryInterface(__uuidof(IDXGIDXVKAdapter), reinterpret_cast<void**>(&dxgiVkAdapter)))) { + dxvkAdapter = dxgiVkAdapter->GetDXVKAdapter(); + dxvkInstance = dxgiVkAdapter->GetDXVKInstance(); + } else { + Logger::warn("D3D11CoreCreateDevice: Adapter is not a DXVK adapter"); + DXGI_ADAPTER_DESC desc; + pAdapter->GetDesc(&desc); + + dxvkInstance = new DxvkInstance(); + dxvkAdapter = dxvkInstance->findAdapterByLuid(&desc.AdapterLuid); + + if (dxvkAdapter == nullptr) + dxvkAdapter = dxvkInstance->findAdapterByDeviceId(desc.VendorId, desc.DeviceId); + + if (dxvkAdapter == nullptr) + dxvkAdapter = dxvkInstance->enumAdapters(0); + + if (dxvkAdapter == nullptr) + return E_FAIL; + } + + // Feature levels to probe if the + // application does not specify any. + std::array<D3D_FEATURE_LEVEL, 6> defaultFeatureLevels = { + D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1, + }; + + if (pFeatureLevels == nullptr || FeatureLevels == 0) { + pFeatureLevels = defaultFeatureLevels.data(); + FeatureLevels = defaultFeatureLevels.size(); + } + + // Find the highest feature level supported by the device. + // This works because the feature level array is ordered. + UINT flId; + + for (flId = 0 ; flId < FeatureLevels; flId++) { + Logger::info(str::format("D3D11CoreCreateDevice: Probing ", pFeatureLevels[flId])); + + if (D3D11Device::CheckFeatureLevelSupport(dxvkInstance, dxvkAdapter, pFeatureLevels[flId])) + break; + } + + if (flId == FeatureLevels) { + Logger::err("D3D11CoreCreateDevice: Requested feature level not supported"); + return E_INVALIDARG; + } + + // Try to create the device with the given parameters. + const D3D_FEATURE_LEVEL fl = pFeatureLevels[flId]; + + try { + Logger::info(str::format("D3D11CoreCreateDevice: Using feature level ", fl)); + Com<D3D11DXGIDevice> device = new D3D11DXGIDevice( + pAdapter, dxvkInstance, dxvkAdapter, fl, Flags); + + return device->QueryInterface( + __uuidof(ID3D11Device), + reinterpret_cast<void**>(ppDevice)); + } catch (const DxvkError& e) { + Logger::err("D3D11CoreCreateDevice: Failed to create D3D11 device"); + return E_FAIL; + } + } + + + static HRESULT D3D11InternalCreateDeviceAndSwapChain( + IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + const D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + IDXGISwapChain** ppSwapChain, + ID3D11Device** ppDevice, + D3D_FEATURE_LEVEL* pFeatureLevel, + ID3D11DeviceContext** ppImmediateContext) { + InitReturnPtr(ppDevice); + InitReturnPtr(ppSwapChain); + InitReturnPtr(ppImmediateContext); + + if (pFeatureLevel) + *pFeatureLevel = D3D_FEATURE_LEVEL(0); + + HRESULT hr; + + Com<IDXGIFactory> dxgiFactory = nullptr; + Com<IDXGIAdapter> dxgiAdapter = pAdapter; + Com<ID3D11Device> device = nullptr; + + if (ppSwapChain && !pSwapChainDesc) + return E_INVALIDARG; + + if (!pAdapter) { + // We'll treat everything as hardware, even if the + // Vulkan device is actually a software device. + if (DriverType != D3D_DRIVER_TYPE_HARDWARE) + Logger::warn("D3D11CreateDevice: Unsupported driver type"); + + // We'll use the first adapter returned by a DXGI factory + hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory)); + + if (FAILED(hr)) { + Logger::err("D3D11CreateDevice: Failed to create a DXGI factory"); + return hr; + } + + hr = dxgiFactory->EnumAdapters(0, &dxgiAdapter); + + if (FAILED(hr)) { + Logger::err("D3D11CreateDevice: No default adapter available"); + return hr; + } + } else { + // We should be able to query the DXGI factory from the adapter + if (FAILED(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory)))) { + Logger::err("D3D11CreateDevice: Failed to query DXGI factory from DXGI adapter"); + return E_INVALIDARG; + } + + // In theory we could ignore these, but the Microsoft docs explicitly + // state that we need to return E_INVALIDARG in case the arguments are + // invalid. Both the driver type and software parameter can only be + // set if the adapter itself is unspecified. + // See: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476082(v=vs.85).aspx + if (DriverType != D3D_DRIVER_TYPE_UNKNOWN || Software) + return E_INVALIDARG; + } + + // Create the actual device + hr = D3D11CoreCreateDevice( + dxgiFactory.ptr(), dxgiAdapter.ptr(), + Flags, pFeatureLevels, FeatureLevels, + &device); + + if (FAILED(hr)) + return hr; + + // Create the swap chain, if requested + if (ppSwapChain) { + DXGI_SWAP_CHAIN_DESC desc = *pSwapChainDesc; + hr = dxgiFactory->CreateSwapChain(device.ptr(), &desc, ppSwapChain); + + if (FAILED(hr)) { + Logger::err("D3D11CreateDevice: Failed to create swap chain"); + return hr; + } + } + + // Write back whatever info the application requested + if (pFeatureLevel) + *pFeatureLevel = device->GetFeatureLevel(); + + if (ppDevice) + *ppDevice = device.ref(); + + if (ppImmediateContext) + device->GetImmediateContext(ppImmediateContext); + + // If we were unable to write back the device and the + // swap chain, the application has no way of working + // with the device so we should report S_FALSE here. + if (!ppDevice && !ppImmediateContext && !ppSwapChain) + return S_FALSE; + + return S_OK; + } + + + DLLEXPORT HRESULT __stdcall D3D11CreateDevice( + IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + const D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + ID3D11Device** ppDevice, + D3D_FEATURE_LEVEL* pFeatureLevel, + ID3D11DeviceContext** ppImmediateContext) { + return D3D11InternalCreateDeviceAndSwapChain( + pAdapter, DriverType, Software, Flags, + pFeatureLevels, FeatureLevels, SDKVersion, + nullptr, nullptr, + ppDevice, pFeatureLevel, ppImmediateContext); + } + + + DLLEXPORT HRESULT __stdcall D3D11CreateDeviceAndSwapChain( + IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + const D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, + IDXGISwapChain** ppSwapChain, + ID3D11Device** ppDevice, + D3D_FEATURE_LEVEL* pFeatureLevel, + ID3D11DeviceContext** ppImmediateContext) { + return D3D11InternalCreateDeviceAndSwapChain( + pAdapter, DriverType, Software, Flags, + pFeatureLevels, FeatureLevels, SDKVersion, + pSwapChainDesc, ppSwapChain, + ppDevice, pFeatureLevel, ppImmediateContext); + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.cpp new file mode 100644 index 00000000..3bef2365 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.cpp @@ -0,0 +1,44 @@ +#include <unordered_map> + +#include "d3d11_options.h" + +namespace dxvk { + + D3D11Options::D3D11Options(const Config& config, const Rc<DxvkDevice>& device) { + const DxvkDeviceInfo& devInfo = device->properties(); + + this->dcSingleUseMode = config.getOption<bool>("d3d11.dcSingleUseMode", true); + this->enableRtOutputNanFixup = config.getOption<bool>("d3d11.enableRtOutputNanFixup", false); + this->zeroInitWorkgroupMemory = config.getOption<bool>("d3d11.zeroInitWorkgroupMemory", false); + this->forceTgsmBarriers = config.getOption<bool>("d3d11.forceTgsmBarriers", false); + this->relaxedBarriers = config.getOption<bool>("d3d11.relaxedBarriers", false); + this->ignoreGraphicsBarriers = config.getOption<bool>("d3d11.ignoreGraphicsBarriers", false); + this->maxTessFactor = config.getOption<int32_t>("d3d11.maxTessFactor", 0); + this->samplerAnisotropy = config.getOption<int32_t>("d3d11.samplerAnisotropy", -1); + this->invariantPosition = config.getOption<bool>("d3d11.invariantPosition", true); + this->floatControls = config.getOption<bool>("d3d11.floatControls", true); + this->disableMsaa = config.getOption<bool>("d3d11.disableMsaa", false); + this->deferSurfaceCreation = config.getOption<bool>("dxgi.deferSurfaceCreation", false); + this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0); + this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0); + this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0); + this->syncInterval = config.getOption<int32_t>("dxgi.syncInterval", -1); + this->tearFree = config.getOption<Tristate>("dxgi.tearFree", Tristate::Auto); + + this->constantBufferRangeCheck = config.getOption<bool>("d3d11.constantBufferRangeCheck", false) + && DxvkGpuVendor(devInfo.core.properties.vendorID) != DxvkGpuVendor::Amd; + + bool apitraceAttached = false; + #if !defined(DXVK_NATIVE) + apitraceAttached = ::GetModuleHandle("dxgitrace.dll") != nullptr; + #endif + + this->apitraceMode = config.getOption<bool>("d3d11.apitraceMode", apitraceAttached); + + // Inform user in case they have the option enabled or a game + // ships a file called dxgitrace.dll for whatever reason. + if (this->apitraceMode) + Logger::warn("D3D11: Apitrace mode enabled, may affect performance!"); + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.h new file mode 100644 index 00000000..40a76aca --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.h @@ -0,0 +1,109 @@ +#pragma once + +#include "../util/config/config.h" + +#include "../dxgi/dxgi_options.h" + +#include "../dxvk/dxvk_device.h" + +#include "d3d11_include.h" + +namespace dxvk { + + struct D3D11Options { + D3D11Options(const Config& config, const Rc<DxvkDevice>& device); + + /// Enables speed hack for mapping on deferred contexts + /// + /// This can substantially speed up some games, but may + /// cause issues if the game submits command lists more + /// than once. + bool dcSingleUseMode; + + /// Enables workaround to replace NaN render target + /// outputs with zero + bool enableRtOutputNanFixup; + + /// Enables out-of-bounds access check for constant + /// buffers. Workaround for a few broken games that + /// access random data inside their shaders. + bool constantBufferRangeCheck; + + /// Zero-initialize workgroup memory + /// + /// Workargound for games that don't initialize + /// TGSM in compute shaders before reading it. + bool zeroInitWorkgroupMemory; + + /// Force thread-group shared memory barriers + /// + /// Workaround for compute shaders that read and + /// write from the same shared memory location + /// without explicit synchronization. + bool forceTgsmBarriers; + + /// Use relaxed memory barriers + /// + /// May improve performance in some games, + /// but might also cause rendering issues. + bool relaxedBarriers; + + /// Ignore graphics barriers + /// + /// May improve performance in some games, + /// but might also cause rendering issues. + bool ignoreGraphicsBarriers; + + /// Maximum tessellation factor. + /// + /// Limits tessellation factors in tessellation + /// control shaders. Values from 8 to 64 are + /// supported, other values will be ignored. + int32_t maxTessFactor; + + /// Anisotropic filter override + /// + /// Enforces anisotropic filtering with the + /// given anisotropy value for all samplers. + int32_t samplerAnisotropy; + + /// Declare vertex positions in shaders as invariant + bool invariantPosition; + + /// Enable float control bits + bool floatControls; + + /// Back buffer count for the Vulkan swap chain. + /// Overrides DXGI_SWAP_CHAIN_DESC::BufferCount. + int32_t numBackBuffers; + + /// Sync interval. Overrides the value + /// passed to IDXGISwapChain::Present. + int32_t syncInterval; + + /// Tear-free mode if vsync is disabled + /// Tearing mode if vsync is enabled + Tristate tearFree; + + /// Override maximum frame latency if the app specifies + /// a higher value. May help with frame timing issues. + int32_t maxFrameLatency; + + /// Limit frame rate + int32_t maxFrameRate; + + /// Defer surface creation until first present call. This + /// fixes issues with games that create multiple swap chains + /// for a single window that may interfere with each other. + bool deferSurfaceCreation; + + /// Forces the sample count of all textures to be 1, and + /// performs the required shader and resolve fixups. + bool disableMsaa; + + /// Apitrace mode: Maps all buffers in cached memory. + /// Enabled automatically if dxgitrace.dll is attached. + bool apitraceMode; + }; + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.cpp new file mode 100644 index 00000000..b7145739 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.cpp @@ -0,0 +1,352 @@ +#include "d3d11_device.h" +#include "d3d11_query.h" + +namespace dxvk { + + D3D11Query::D3D11Query( + D3D11Device* device, + const D3D11_QUERY_DESC1& desc) + : D3D11DeviceChild<ID3D11Query1>(device), + m_desc(desc), + m_state(D3D11_VK_QUERY_INITIAL), + m_d3d10(this) { + Rc<DxvkDevice> dxvkDevice = m_parent->GetDXVKDevice(); + + switch (m_desc.Query) { + case D3D11_QUERY_EVENT: + m_event[0] = dxvkDevice->createGpuEvent(); + break; + + case D3D11_QUERY_OCCLUSION: + m_query[0] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_OCCLUSION, + VK_QUERY_CONTROL_PRECISE_BIT, 0); + break; + + case D3D11_QUERY_OCCLUSION_PREDICATE: + m_query[0] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_OCCLUSION, 0, 0); + break; + + case D3D11_QUERY_TIMESTAMP: + m_query[0] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_TIMESTAMP, 0, 0); + break; + + case D3D11_QUERY_TIMESTAMP_DISJOINT: + for (uint32_t i = 0; i < 2; i++) { + m_query[i] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_TIMESTAMP, 0, 0); + } + break; + + case D3D11_QUERY_PIPELINE_STATISTICS: + m_query[0] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0); + break; + + case D3D11_QUERY_SO_STATISTICS: + case D3D11_QUERY_SO_STATISTICS_STREAM0: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0: + // FIXME it is technically incorrect to map + // SO_OVERFLOW_PREDICATE to the first stream, + // but this is good enough for D3D10 behaviour + m_query[0] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 0); + break; + + case D3D11_QUERY_SO_STATISTICS_STREAM1: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1: + m_query[0] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 1); + break; + + case D3D11_QUERY_SO_STATISTICS_STREAM2: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2: + m_query[0] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 2); + break; + + case D3D11_QUERY_SO_STATISTICS_STREAM3: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3: + m_query[0] = dxvkDevice->createGpuQuery( + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 3); + break; + + default: + throw DxvkError(str::format("D3D11: Unhandled query type: ", desc.Query)); + } + } + + + D3D11Query::~D3D11Query() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11Query::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11Asynchronous) + || riid == __uuidof(ID3D11Query) + || riid == __uuidof(ID3D11Query1)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10Asynchronous) + || riid == __uuidof(ID3D10Query)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + if (m_desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE) { + if (riid == __uuidof(ID3D11Predicate)) { + *ppvObject = AsPredicate(ref(this)); + return S_OK; + } + + if (riid == __uuidof(ID3D10Predicate)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + } + + Logger::warn("D3D11Query: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + UINT STDMETHODCALLTYPE D3D11Query::GetDataSize() { + switch (m_desc.Query) { + case D3D11_QUERY_EVENT: + return sizeof(BOOL); + + case D3D11_QUERY_OCCLUSION: + return sizeof(UINT64); + + case D3D11_QUERY_TIMESTAMP: + return sizeof(UINT64); + + case D3D11_QUERY_TIMESTAMP_DISJOINT: + return sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT); + + case D3D11_QUERY_PIPELINE_STATISTICS: + return sizeof(D3D11_QUERY_DATA_PIPELINE_STATISTICS); + + case D3D11_QUERY_OCCLUSION_PREDICATE: + return sizeof(BOOL); + + case D3D11_QUERY_SO_STATISTICS: + case D3D11_QUERY_SO_STATISTICS_STREAM0: + case D3D11_QUERY_SO_STATISTICS_STREAM1: + case D3D11_QUERY_SO_STATISTICS_STREAM2: + case D3D11_QUERY_SO_STATISTICS_STREAM3: + return sizeof(D3D11_QUERY_DATA_SO_STATISTICS); + + case D3D11_QUERY_SO_OVERFLOW_PREDICATE: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3: + return sizeof(BOOL); + } + + Logger::err("D3D11Query: Failed to query data size"); + return 0; + } + + + void STDMETHODCALLTYPE D3D11Query::GetDesc(D3D11_QUERY_DESC* pDesc) { + pDesc->Query = m_desc.Query; + pDesc->MiscFlags = m_desc.MiscFlags; + } + + + void STDMETHODCALLTYPE D3D11Query::GetDesc1(D3D11_QUERY_DESC1* pDesc) { + *pDesc = m_desc; + } + + + void D3D11Query::Begin(DxvkContext* ctx) { + switch (m_desc.Query) { + case D3D11_QUERY_EVENT: + case D3D11_QUERY_TIMESTAMP: + break; + + case D3D11_QUERY_TIMESTAMP_DISJOINT: + ctx->writeTimestamp(m_query[1]); + break; + + default: + ctx->beginQuery(m_query[0]); + } + } + + + void D3D11Query::End(DxvkContext* ctx) { + switch (m_desc.Query) { + case D3D11_QUERY_EVENT: + ctx->signalGpuEvent(m_event[0]); + break; + + case D3D11_QUERY_TIMESTAMP: + case D3D11_QUERY_TIMESTAMP_DISJOINT: + ctx->writeTimestamp(m_query[0]); + break; + + default: + ctx->endQuery(m_query[0]); + } + + m_resetCtr.fetch_sub(1, std::memory_order_release); + } + + + bool STDMETHODCALLTYPE D3D11Query::DoBegin() { + if (!IsScoped() || m_state == D3D11_VK_QUERY_BEGUN) + return false; + + m_state = D3D11_VK_QUERY_BEGUN; + return true; + } + + bool STDMETHODCALLTYPE D3D11Query::DoEnd() { + // Apparently the D3D11 runtime implicitly begins the query + // if it is in the wrong state at the time End is called, so + // let the caller react to it instead of just failing here. + bool result = m_state == D3D11_VK_QUERY_BEGUN || !IsScoped(); + + m_state = D3D11_VK_QUERY_ENDED; + m_resetCtr.fetch_add(1, std::memory_order_acquire); + return result; + } + + + HRESULT STDMETHODCALLTYPE D3D11Query::GetData( + void* pData, + UINT GetDataFlags) { + if (m_state != D3D11_VK_QUERY_ENDED) + return DXGI_ERROR_INVALID_CALL; + + if (m_resetCtr != 0u) + return S_FALSE; + + if (m_desc.Query == D3D11_QUERY_EVENT) { + DxvkGpuEventStatus status = m_event[0]->test(); + + if (status == DxvkGpuEventStatus::Invalid) + return DXGI_ERROR_INVALID_CALL; + + bool signaled = status == DxvkGpuEventStatus::Signaled; + + if (pData != nullptr) + *static_cast<BOOL*>(pData) = signaled; + + return signaled ? S_OK : S_FALSE; + } else { + std::array<DxvkQueryData, MaxGpuQueries> queryData = { }; + + for (uint32_t i = 0; i < MaxGpuQueries && m_query[i] != nullptr; i++) { + DxvkGpuQueryStatus status = m_query[i]->getData(queryData[i]); + + if (status == DxvkGpuQueryStatus::Invalid + || status == DxvkGpuQueryStatus::Failed) + return DXGI_ERROR_INVALID_CALL; + + if (status == DxvkGpuQueryStatus::Pending) + return S_FALSE; + } + + if (pData == nullptr) + return S_OK; + + switch (m_desc.Query) { + case D3D11_QUERY_OCCLUSION: + *static_cast<UINT64*>(pData) = queryData[0].occlusion.samplesPassed; + return S_OK; + + case D3D11_QUERY_OCCLUSION_PREDICATE: + *static_cast<BOOL*>(pData) = queryData[0].occlusion.samplesPassed != 0; + return S_OK; + + case D3D11_QUERY_TIMESTAMP: + *static_cast<UINT64*>(pData) = queryData[0].timestamp.time; + return S_OK; + + case D3D11_QUERY_TIMESTAMP_DISJOINT: { + auto data = static_cast<D3D11_QUERY_DATA_TIMESTAMP_DISJOINT*>(pData); + data->Frequency = GetTimestampQueryFrequency(); + data->Disjoint = queryData[0].timestamp.time < queryData[1].timestamp.time; + } return S_OK; + + case D3D11_QUERY_PIPELINE_STATISTICS: { + auto data = static_cast<D3D11_QUERY_DATA_PIPELINE_STATISTICS*>(pData); + data->IAVertices = queryData[0].statistic.iaVertices; + data->IAPrimitives = queryData[0].statistic.iaPrimitives; + data->VSInvocations = queryData[0].statistic.vsInvocations; + data->GSInvocations = queryData[0].statistic.gsInvocations; + data->GSPrimitives = queryData[0].statistic.gsPrimitives; + data->CInvocations = queryData[0].statistic.clipInvocations; + data->CPrimitives = queryData[0].statistic.clipPrimitives; + data->PSInvocations = queryData[0].statistic.fsInvocations; + data->HSInvocations = queryData[0].statistic.tcsPatches; + data->DSInvocations = queryData[0].statistic.tesInvocations; + data->CSInvocations = queryData[0].statistic.csInvocations; + } return S_OK; + + case D3D11_QUERY_SO_STATISTICS: + case D3D11_QUERY_SO_STATISTICS_STREAM0: + case D3D11_QUERY_SO_STATISTICS_STREAM1: + case D3D11_QUERY_SO_STATISTICS_STREAM2: + case D3D11_QUERY_SO_STATISTICS_STREAM3: { + auto data = static_cast<D3D11_QUERY_DATA_SO_STATISTICS*>(pData); + data->NumPrimitivesWritten = queryData[0].xfbStream.primitivesWritten; + data->PrimitivesStorageNeeded = queryData[0].xfbStream.primitivesNeeded; + } return S_OK; + + case D3D11_QUERY_SO_OVERFLOW_PREDICATE: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2: + case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3: { + auto data = static_cast<BOOL*>(pData); + *data = queryData[0].xfbStream.primitivesNeeded + > queryData[0].xfbStream.primitivesWritten; + } return S_OK; + + default: + Logger::err(str::format("D3D11: Unhandled query type in GetData: ", m_desc.Query)); + return E_INVALIDARG; + } + } + } + + + UINT64 D3D11Query::GetTimestampQueryFrequency() const { + Rc<DxvkDevice> device = m_parent->GetDXVKDevice(); + Rc<DxvkAdapter> adapter = device->adapter(); + + VkPhysicalDeviceLimits limits = adapter->deviceProperties().limits; + return uint64_t(1'000'000'000.0f / limits.timestampPeriod); + } + + + HRESULT D3D11Query::ValidateDesc(const D3D11_QUERY_DESC1* pDesc) { + if (pDesc->Query >= D3D11_QUERY_PIPELINE_STATISTICS + && pDesc->ContextType > D3D11_CONTEXT_TYPE_3D) + return E_INVALIDARG; + + return S_OK; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.h new file mode 100644 index 00000000..06ac4a1a --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.h @@ -0,0 +1,114 @@ +#pragma once + +#include "../dxvk/dxvk_gpu_event.h" +#include "../dxvk/dxvk_gpu_query.h" + +#include "../d3d10/d3d10_query.h" + +#include "d3d11_device_child.h" + +namespace dxvk { + + enum D3D11_VK_QUERY_STATE : uint32_t { + D3D11_VK_QUERY_INITIAL, + D3D11_VK_QUERY_BEGUN, + D3D11_VK_QUERY_ENDED, + }; + + class D3D11Query : public D3D11DeviceChild<ID3D11Query1> { + constexpr static uint32_t MaxGpuQueries = 2; + constexpr static uint32_t MaxGpuEvents = 1; + public: + + D3D11Query( + D3D11Device* device, + const D3D11_QUERY_DESC1& desc); + + ~D3D11Query(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + UINT STDMETHODCALLTYPE GetDataSize(); + + void STDMETHODCALLTYPE GetDesc(D3D11_QUERY_DESC* pDesc) final; + + void STDMETHODCALLTYPE GetDesc1(D3D11_QUERY_DESC1* pDesc) final; + + void Begin(DxvkContext* ctx); + + void End(DxvkContext* ctx); + + bool STDMETHODCALLTYPE DoBegin(); + + bool STDMETHODCALLTYPE DoEnd(); + + HRESULT STDMETHODCALLTYPE GetData( + void* pData, + UINT GetDataFlags); + + void DoDeferredEnd() { + m_state = D3D11_VK_QUERY_ENDED; + m_resetCtr.fetch_add(1, std::memory_order_acquire); + } + + bool IsScoped() const { + return m_desc.Query != D3D11_QUERY_EVENT + && m_desc.Query != D3D11_QUERY_TIMESTAMP; + } + + bool IsEvent() const { + return m_desc.Query == D3D11_QUERY_EVENT; + } + + bool IsStalling() const { + return m_stallFlag; + } + + void NotifyEnd() { + m_stallMask <<= 1; + } + + void NotifyStall() { + m_stallMask |= 1; + m_stallFlag |= bit::popcnt(m_stallMask) >= 16; + } + + D3D10Query* GetD3D10Iface() { + return &m_d3d10; + } + + static HRESULT ValidateDesc(const D3D11_QUERY_DESC1* pDesc); + + static ID3D11Predicate* AsPredicate(ID3D11Query* pQuery) { + // ID3D11Predicate and ID3D11Query have the same vtable. This + // saves us some headache in all query-related functions. + return static_cast<ID3D11Predicate*>(pQuery); + } + + static D3D11Query* FromPredicate(ID3D11Predicate* pPredicate) { + return static_cast<D3D11Query*>(static_cast<ID3D11Query*>(pPredicate)); + } + + private: + + D3D11_QUERY_DESC1 m_desc; + + D3D11_VK_QUERY_STATE m_state; + + std::array<Rc<DxvkGpuQuery>, MaxGpuQueries> m_query; + std::array<Rc<DxvkGpuEvent>, MaxGpuEvents> m_event; + + D3D10Query m_d3d10; + + uint32_t m_stallMask = 0; + bool m_stallFlag = false; + + std::atomic<uint32_t> m_resetCtr = { 0u }; + + UINT64 GetTimestampQueryFrequency() const; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.cpp new file mode 100644 index 00000000..6d70847e --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.cpp @@ -0,0 +1,195 @@ +#include "d3d11_device.h" +#include "d3d11_rasterizer.h" + +namespace dxvk { + + D3D11RasterizerState::D3D11RasterizerState( + D3D11Device* device, + const D3D11_RASTERIZER_DESC2& desc) + : D3D11StateObject<ID3D11RasterizerState2>(device), + m_desc(desc), m_d3d10(this) { + // Polygon mode. Determines whether the rasterizer fills + // a polygon or renders lines connecting the vertices. + switch (desc.FillMode) { + default: + case D3D11_FILL_SOLID: m_state.polygonMode = VK_POLYGON_MODE_FILL; break; + case D3D11_FILL_WIREFRAME: m_state.polygonMode = VK_POLYGON_MODE_LINE; break; + } + + // Face culling properties. The rasterizer may discard + // polygons that are facing towards or away from the + // viewer, depending on the options below. + switch (desc.CullMode) { + default: + case D3D11_CULL_NONE: m_state.cullMode = VK_CULL_MODE_NONE; break; + case D3D11_CULL_FRONT: m_state.cullMode = VK_CULL_MODE_FRONT_BIT; break; + case D3D11_CULL_BACK: m_state.cullMode = VK_CULL_MODE_BACK_BIT; break; + } + + m_state.frontFace = desc.FrontCounterClockwise + ? VK_FRONT_FACE_COUNTER_CLOCKWISE + : VK_FRONT_FACE_CLOCKWISE; + + // In the backend we treat depth bias as a dynamic state because + // some games like to put random/uninitialized numbers here, but + // we do not need to enable it in case the parameters are both 0. + m_state.depthBiasEnable = desc.DepthBias != 0 || desc.SlopeScaledDepthBias != 0.0f; + m_state.depthClipEnable = desc.DepthClipEnable; + m_state.conservativeMode = DecodeConservativeRasterizationMode(desc.ConservativeRaster); + m_state.sampleCount = VkSampleCountFlags(desc.ForcedSampleCount); + + m_depthBias.depthBiasConstant = float(desc.DepthBias); + m_depthBias.depthBiasSlope = desc.SlopeScaledDepthBias; + m_depthBias.depthBiasClamp = desc.DepthBiasClamp; + + if (desc.AntialiasedLineEnable) + Logger::err("D3D11RasterizerState: Antialiased lines not supported"); + } + + + D3D11RasterizerState::~D3D11RasterizerState() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11RasterizerState::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11RasterizerState) + || riid == __uuidof(ID3D11RasterizerState1) + || riid == __uuidof(ID3D11RasterizerState2)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10RasterizerState)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + Logger::warn("D3D11RasterizerState::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11RasterizerState::GetDesc(D3D11_RASTERIZER_DESC* pDesc) { + pDesc->FillMode = m_desc.FillMode; + pDesc->CullMode = m_desc.CullMode; + pDesc->FrontCounterClockwise = m_desc.FrontCounterClockwise; + pDesc->DepthBias = m_desc.DepthBias; + pDesc->DepthBiasClamp = m_desc.DepthBiasClamp; + pDesc->SlopeScaledDepthBias = m_desc.SlopeScaledDepthBias; + pDesc->DepthClipEnable = m_desc.DepthClipEnable; + pDesc->ScissorEnable = m_desc.ScissorEnable; + pDesc->MultisampleEnable = m_desc.MultisampleEnable; + pDesc->AntialiasedLineEnable = m_desc.AntialiasedLineEnable; + } + + + void STDMETHODCALLTYPE D3D11RasterizerState::GetDesc1(D3D11_RASTERIZER_DESC1* pDesc) { + pDesc->FillMode = m_desc.FillMode; + pDesc->CullMode = m_desc.CullMode; + pDesc->FrontCounterClockwise = m_desc.FrontCounterClockwise; + pDesc->DepthBias = m_desc.DepthBias; + pDesc->DepthBiasClamp = m_desc.DepthBiasClamp; + pDesc->SlopeScaledDepthBias = m_desc.SlopeScaledDepthBias; + pDesc->DepthClipEnable = m_desc.DepthClipEnable; + pDesc->ScissorEnable = m_desc.ScissorEnable; + pDesc->MultisampleEnable = m_desc.MultisampleEnable; + pDesc->AntialiasedLineEnable = m_desc.AntialiasedLineEnable; + pDesc->ForcedSampleCount = m_desc.ForcedSampleCount; + } + + + void STDMETHODCALLTYPE D3D11RasterizerState::GetDesc2(D3D11_RASTERIZER_DESC2* pDesc) { + *pDesc = m_desc; + } + + + void D3D11RasterizerState::BindToContext(const Rc<DxvkContext>& ctx) { + ctx->setRasterizerState(m_state); + + if (m_state.depthBiasEnable) + ctx->setDepthBias(m_depthBias); + } + + + D3D11_RASTERIZER_DESC2 D3D11RasterizerState::PromoteDesc( + const D3D11_RASTERIZER_DESC* pSrcDesc) { + D3D11_RASTERIZER_DESC2 dstDesc; + dstDesc.FillMode = pSrcDesc->FillMode; + dstDesc.CullMode = pSrcDesc->CullMode; + dstDesc.FrontCounterClockwise = pSrcDesc->FrontCounterClockwise; + dstDesc.DepthBias = pSrcDesc->DepthBias; + dstDesc.DepthBiasClamp = pSrcDesc->DepthBiasClamp; + dstDesc.SlopeScaledDepthBias = pSrcDesc->SlopeScaledDepthBias; + dstDesc.DepthClipEnable = pSrcDesc->DepthClipEnable; + dstDesc.ScissorEnable = pSrcDesc->ScissorEnable; + dstDesc.MultisampleEnable = pSrcDesc->MultisampleEnable; + dstDesc.AntialiasedLineEnable = pSrcDesc->AntialiasedLineEnable; + dstDesc.ForcedSampleCount = 0; + dstDesc.ConservativeRaster = D3D11_CONSERVATIVE_RASTERIZATION_MODE_OFF; + return dstDesc; + } + + + D3D11_RASTERIZER_DESC2 D3D11RasterizerState::PromoteDesc( + const D3D11_RASTERIZER_DESC1* pSrcDesc) { + D3D11_RASTERIZER_DESC2 dstDesc; + dstDesc.FillMode = pSrcDesc->FillMode; + dstDesc.CullMode = pSrcDesc->CullMode; + dstDesc.FrontCounterClockwise = pSrcDesc->FrontCounterClockwise; + dstDesc.DepthBias = pSrcDesc->DepthBias; + dstDesc.DepthBiasClamp = pSrcDesc->DepthBiasClamp; + dstDesc.SlopeScaledDepthBias = pSrcDesc->SlopeScaledDepthBias; + dstDesc.DepthClipEnable = pSrcDesc->DepthClipEnable; + dstDesc.ScissorEnable = pSrcDesc->ScissorEnable; + dstDesc.MultisampleEnable = pSrcDesc->MultisampleEnable; + dstDesc.AntialiasedLineEnable = pSrcDesc->AntialiasedLineEnable; + dstDesc.ForcedSampleCount = 0; + dstDesc.ConservativeRaster = D3D11_CONSERVATIVE_RASTERIZATION_MODE_OFF; + return dstDesc; + } + + + HRESULT D3D11RasterizerState::NormalizeDesc( + D3D11_RASTERIZER_DESC2* pDesc) { + if (pDesc->FillMode < D3D11_FILL_WIREFRAME + || pDesc->FillMode > D3D11_FILL_SOLID) + return E_INVALIDARG; + + if (pDesc->CullMode < D3D11_CULL_NONE + || pDesc->CullMode > D3D11_CULL_BACK) + return E_INVALIDARG; + + if (pDesc->FrontCounterClockwise) + pDesc->FrontCounterClockwise = TRUE; + + if (pDesc->DepthClipEnable) + pDesc->DepthClipEnable = TRUE; + + if (pDesc->ScissorEnable) + pDesc->ScissorEnable = TRUE; + + if (pDesc->MultisampleEnable) + pDesc->MultisampleEnable = TRUE; + + if (pDesc->AntialiasedLineEnable) + pDesc->AntialiasedLineEnable = TRUE; + + if (pDesc->ForcedSampleCount != 0) { + if (FAILED(DecodeSampleCount(pDesc->ForcedSampleCount, nullptr))) + return E_INVALIDARG; + } + + return S_OK; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.h new file mode 100644 index 00000000..7b542f2c --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.h @@ -0,0 +1,66 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_rasterizer.h" + +#include "d3d11_device_child.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11RasterizerState : public D3D11StateObject<ID3D11RasterizerState2> { + + public: + + using DescType = D3D11_RASTERIZER_DESC2; + + D3D11RasterizerState( + D3D11Device* device, + const D3D11_RASTERIZER_DESC2& desc); + ~D3D11RasterizerState(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void STDMETHODCALLTYPE GetDesc( + D3D11_RASTERIZER_DESC* pDesc) final; + + void STDMETHODCALLTYPE GetDesc1( + D3D11_RASTERIZER_DESC1* pDesc) final; + + void STDMETHODCALLTYPE GetDesc2( + D3D11_RASTERIZER_DESC2* pDesc) final; + + const D3D11_RASTERIZER_DESC2* Desc() const { + return &m_desc; + } + + void BindToContext( + const Rc<DxvkContext>& ctx); + + D3D10RasterizerState* GetD3D10Iface() { + return &m_d3d10; + } + + static D3D11_RASTERIZER_DESC2 PromoteDesc( + const D3D11_RASTERIZER_DESC* pDesc); + + static D3D11_RASTERIZER_DESC2 PromoteDesc( + const D3D11_RASTERIZER_DESC1* pDesc); + + static HRESULT NormalizeDesc( + D3D11_RASTERIZER_DESC2* pDesc); + + private: + + D3D11_RASTERIZER_DESC2 m_desc; + DxvkRasterizerState m_state; + DxvkDepthBias m_depthBias; + D3D10RasterizerState m_d3d10; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.cpp new file mode 100644 index 00000000..7ba71367 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.cpp @@ -0,0 +1,228 @@ +#include "d3d11_buffer.h" +#include "d3d11_texture.h" +#include "d3d11_resource.h" + +namespace dxvk { + + D3D11DXGIResource::D3D11DXGIResource( + ID3D11Resource* pResource) + : m_resource(pResource) { + + } + + + D3D11DXGIResource::~D3D11DXGIResource() { + + } + + + ULONG STDMETHODCALLTYPE D3D11DXGIResource::AddRef() { + return m_resource->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11DXGIResource::Release() { + return m_resource->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_resource->QueryInterface(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetPrivateData( + REFGUID Name, + UINT* pDataSize, + void* pData) { + return m_resource->GetPrivateData(Name, pDataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::SetPrivateData( + REFGUID Name, + UINT DataSize, + const void* pData) { + return m_resource->SetPrivateData(Name, DataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::SetPrivateDataInterface( + REFGUID Name, + const IUnknown* pUnknown) { + return m_resource->SetPrivateDataInterface(Name, pUnknown); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetParent( + REFIID riid, + void** ppParent) { + return GetDevice(riid, ppParent); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetDevice( + REFIID riid, + void** ppDevice) { + Com<ID3D11Device> device; + m_resource->GetDevice(&device); + return device->QueryInterface(riid, ppDevice); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetEvictionPriority( + UINT* pEvictionPriority) { + *pEvictionPriority = m_resource->GetEvictionPriority(); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetSharedHandle( + HANDLE* pSharedHandle) { + InitReturnPtr(pSharedHandle); + Logger::err("D3D11DXGIResource::GetSharedHandle: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetUsage( + DXGI_USAGE* pUsage) { + D3D11_COMMON_RESOURCE_DESC desc; + + HRESULT hr = GetCommonResourceDesc(m_resource, &desc); + + if (FAILED(hr)) + return hr; + + DXGI_USAGE usage = desc.DxgiUsage; + + switch (desc.Usage) { + case D3D11_USAGE_IMMUTABLE: usage |= DXGI_CPU_ACCESS_NONE; break; + case D3D11_USAGE_DEFAULT: usage |= DXGI_CPU_ACCESS_NONE; break; + case D3D11_USAGE_DYNAMIC: usage |= DXGI_CPU_ACCESS_DYNAMIC; break; + case D3D11_USAGE_STAGING: usage |= DXGI_CPU_ACCESS_READ_WRITE; break; + } + + // TODO add flags for swap chain back buffers + if (desc.BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_CONSTANT_BUFFER)) + usage |= DXGI_USAGE_SHADER_INPUT; + + if (desc.BindFlags & D3D11_BIND_RENDER_TARGET) + usage |= DXGI_USAGE_RENDER_TARGET_OUTPUT; + + if (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) + usage |= DXGI_USAGE_UNORDERED_ACCESS; + + *pUsage = usage; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::SetEvictionPriority( + UINT EvictionPriority) { + m_resource->SetEvictionPriority(EvictionPriority); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::CreateSharedHandle( + const SECURITY_ATTRIBUTES* pAttributes, + DWORD dwAccess, + LPCWSTR lpName, + HANDLE* pHandle) { + InitReturnPtr(pHandle); + Logger::err("D3D11DXGIResource::CreateSharedHandle: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGIResource::CreateSubresourceSurface( + UINT index, + IDXGISurface2** ppSurface) { + InitReturnPtr(ppSurface); + Logger::err("D3D11DXGIResource::CreateSubresourceSurface: Stub"); + return E_NOTIMPL; + } + + + HRESULT GetCommonResourceDesc( + ID3D11Resource* pResource, + D3D11_COMMON_RESOURCE_DESC* pDesc) { + auto buffer = GetCommonBuffer (pResource); + auto texture = GetCommonTexture(pResource); + + if (buffer != nullptr) { + pDesc->Dim = D3D11_RESOURCE_DIMENSION_BUFFER; + pDesc->Format = DXGI_FORMAT_UNKNOWN; + pDesc->Usage = buffer->Desc()->Usage; + pDesc->BindFlags = buffer->Desc()->BindFlags; + pDesc->CPUAccessFlags = buffer->Desc()->CPUAccessFlags; + pDesc->MiscFlags = buffer->Desc()->MiscFlags; + pDesc->DxgiUsage = 0; + return S_OK; + } else if (texture != nullptr) { + pResource->GetType(&pDesc->Dim); + pDesc->Format = texture->Desc()->Format; + pDesc->Usage = texture->Desc()->Usage; + pDesc->BindFlags = texture->Desc()->BindFlags; + pDesc->CPUAccessFlags = texture->Desc()->CPUAccessFlags; + pDesc->MiscFlags = texture->Desc()->MiscFlags; + pDesc->DxgiUsage = texture->GetDxgiUsage(); + return S_OK; + } else { + pDesc->Dim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pDesc->Format = DXGI_FORMAT_UNKNOWN; + pDesc->Usage = D3D11_USAGE_DEFAULT; + pDesc->BindFlags = 0; + pDesc->CPUAccessFlags = 0; + pDesc->MiscFlags = 0; + pDesc->DxgiUsage = 0; + return E_INVALIDARG; + } + } + + + BOOL CheckResourceViewCompatibility( + ID3D11Resource* pResource, + UINT BindFlags, + DXGI_FORMAT Format, + UINT Plane) { + auto texture = GetCommonTexture(pResource); + auto buffer = GetCommonBuffer (pResource); + + return texture != nullptr + ? texture->CheckViewCompatibility(BindFlags, Format, Plane) + : buffer ->CheckViewCompatibility(BindFlags, Format); + } + + + HRESULT ResourceAddRefPrivate(ID3D11Resource* pResource) { + D3D11_RESOURCE_DIMENSION dim; + pResource->GetType(&dim); + + switch (dim) { + case D3D11_RESOURCE_DIMENSION_BUFFER: static_cast<D3D11Buffer*> (pResource)->AddRefPrivate(); return S_OK; + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: static_cast<D3D11Texture1D*>(pResource)->AddRefPrivate(); return S_OK; + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: static_cast<D3D11Texture2D*>(pResource)->AddRefPrivate(); return S_OK; + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: static_cast<D3D11Texture3D*>(pResource)->AddRefPrivate(); return S_OK; + default: return E_INVALIDARG; + } + } + + + HRESULT ResourceReleasePrivate(ID3D11Resource* pResource) { + D3D11_RESOURCE_DIMENSION dim; + pResource->GetType(&dim); + + switch (dim) { + case D3D11_RESOURCE_DIMENSION_BUFFER: static_cast<D3D11Buffer*> (pResource)->ReleasePrivate(); return S_OK; + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: static_cast<D3D11Texture1D*>(pResource)->ReleasePrivate(); return S_OK; + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: static_cast<D3D11Texture2D*>(pResource)->ReleasePrivate(); return S_OK; + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: static_cast<D3D11Texture3D*>(pResource)->ReleasePrivate(); return S_OK; + default: return E_INVALIDARG; + } + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.h new file mode 100644 index 00000000..7d91a305 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.h @@ -0,0 +1,147 @@ +#pragma once + +#include "d3d11_include.h" + +namespace dxvk { + + /** + * \brief Common resource description + * + * Stores the usage and bind flags of a resource + * Can be used to quickly determine whether it is + * legal to create a view for a given resource. + */ + struct D3D11_COMMON_RESOURCE_DESC { + D3D11_RESOURCE_DIMENSION Dim; + DXGI_FORMAT Format; + D3D11_USAGE Usage; + UINT BindFlags; + UINT CPUAccessFlags; + UINT MiscFlags; + UINT DxgiUsage; + }; + + + /** + * \brief IDXGIResource implementation for D3D11 resources + */ + class D3D11DXGIResource : public IDXGIResource1 { + + public: + + D3D11DXGIResource( + ID3D11Resource* pResource); + + ~D3D11DXGIResource(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE GetPrivateData( + REFGUID Name, + UINT* pDataSize, + void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateData( + REFGUID Name, + UINT DataSize, + const void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + REFGUID Name, + const IUnknown* pUnknown); + + HRESULT STDMETHODCALLTYPE GetParent( + REFIID riid, + void** ppParent); + + HRESULT STDMETHODCALLTYPE GetDevice( + REFIID riid, + void** ppDevice); + + HRESULT STDMETHODCALLTYPE GetEvictionPriority( + UINT* pEvictionPriority); + + HRESULT STDMETHODCALLTYPE GetSharedHandle( + HANDLE* pSharedHandle); + + HRESULT STDMETHODCALLTYPE GetUsage( + DXGI_USAGE* pUsage); + + HRESULT STDMETHODCALLTYPE SetEvictionPriority( + UINT EvictionPriority); + + HRESULT STDMETHODCALLTYPE CreateSharedHandle( + const SECURITY_ATTRIBUTES* pAttributes, + DWORD dwAccess, + LPCWSTR lpName, + HANDLE* pHandle); + + HRESULT STDMETHODCALLTYPE CreateSubresourceSurface( + UINT index, + IDXGISurface2** ppSurface); + + private: + + ID3D11Resource* m_resource; + + }; + + + /** + * \brief Queries common resource description + * + * \param [in] pResource The resource to query + * \param [out] pDesc Resource description + * \returns \c S_OK on success, or \c E_INVALIDARG + */ + HRESULT GetCommonResourceDesc( + ID3D11Resource* pResource, + D3D11_COMMON_RESOURCE_DESC* pDesc); + + /** + * \brief Checks whether a format can be used to view a resource + * + * Depending on whether the resource is a buffer or a + * texture, certain restrictions apply on which formats + * can be used to view the resource. + * \param [in] pResource The resource to check + * \param [in] BindFlags Bind flags required for the view + * \param [in] Format The desired view format + * \param [in] Plane Plane slice for planar formats + * \returns \c true if the format is compatible + */ + BOOL CheckResourceViewCompatibility( + ID3D11Resource* pResource, + UINT BindFlags, + DXGI_FORMAT Format, + UINT Plane); + + /** + * \brief Increments private reference count of a resource + * + * Helper method that figures out the exact type of + * the resource and calls its \c AddRefPrivate method. + * \param [in] pResource The resource to reference + * \returns \c S_OK, or \c E_INVALIDARG for an invalid resource + */ + HRESULT ResourceAddRefPrivate( + ID3D11Resource* pResource); + + /** + * \brief Decrements private reference count of a resource + * + * Helper method that figures out the exact type of + * the resource and calls its \c ReleasePrivate method. + * \param [in] pResource The resource to reference + * \returns \c S_OK, or \c E_INVALIDARG for an invalid resource + */ + HRESULT ResourceReleasePrivate( + ID3D11Resource* pResource); + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.cpp new file mode 100644 index 00000000..397dc47b --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.cpp @@ -0,0 +1,147 @@ +#include "d3d11_device.h" +#include "d3d11_sampler.h" +#include "d3d11_util.h" + +namespace dxvk { + + D3D11SamplerState::D3D11SamplerState( + D3D11Device* device, + const D3D11_SAMPLER_DESC& desc) + : D3D11StateObject<ID3D11SamplerState>(device), + m_desc(desc), m_d3d10(this) { + DxvkSamplerCreateInfo info; + + // While D3D11_FILTER is technically an enum, its value bits + // can be used to decode the filter properties more efficiently. + const uint32_t filterBits = uint32_t(desc.Filter); + info.magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + info.minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + + // Set up the remaining properties, which are + // stored directly in the sampler description + info.mipmapMode = (filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; + info.mipmapLodBias = desc.MipLODBias; + info.mipmapLodMin = desc.MinLOD; + info.mipmapLodMax = desc.MaxLOD; + + info.useAnisotropy = (filterBits & 0x40) ? VK_TRUE : VK_FALSE; + info.maxAnisotropy = float(desc.MaxAnisotropy); + + info.addressModeU = DecodeAddressMode(desc.AddressU); + info.addressModeV = DecodeAddressMode(desc.AddressV); + info.addressModeW = DecodeAddressMode(desc.AddressW); + + info.compareToDepth = (filterBits & 0x80) ? VK_TRUE : VK_FALSE; + info.compareOp = DecodeCompareOp(desc.ComparisonFunc); + + for (uint32_t i = 0; i < 4; i++) + info.borderColor.float32[i] = desc.BorderColor[i]; + + info.usePixelCoord = VK_FALSE; // Not supported in D3D11 + + // Make sure to use a valid anisotropy value + if (desc.MaxAnisotropy < 1) info.maxAnisotropy = 1.0f; + if (desc.MaxAnisotropy > 16) info.maxAnisotropy = 16.0f; + + // Enforce anisotropy specified in the device options + int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy; + + if (samplerAnisotropyOption >= 0) { + info.useAnisotropy = samplerAnisotropyOption > 0; + info.maxAnisotropy = float(samplerAnisotropyOption); + } + + m_sampler = device->GetDXVKDevice()->createSampler(info); + } + + + D3D11SamplerState::~D3D11SamplerState() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11SamplerState::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11SamplerState)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10SamplerState)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + Logger::warn("D3D11SamplerState::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11SamplerState::GetDesc(D3D11_SAMPLER_DESC* pDesc) { + *pDesc = m_desc; + } + + + HRESULT D3D11SamplerState::NormalizeDesc(D3D11_SAMPLER_DESC* pDesc) { + const uint32_t filterBits = uint32_t(pDesc->Filter); + + if (filterBits & 0xFFFFFF2A) { + Logger::err(str::format( + "D3D11SamplerState: Unhandled filter: ", filterBits)); + return E_INVALIDARG; + } + + if (pDesc->MaxAnisotropy < 0 + || pDesc->MaxAnisotropy > 16) { + return E_INVALIDARG; + } else if ((filterBits & 0x40) == 0 /* not anisotropic */) { + // Reset anisotropy if it is not used + pDesc->MaxAnisotropy = 0; + } + + if (filterBits & 0x80 /* compare-to-depth */) { + if (!ValidateComparisonFunc(pDesc->ComparisonFunc)) + return E_INVALIDARG; + } else { + // Reset compare func if it is not used + pDesc->ComparisonFunc = D3D11_COMPARISON_NEVER; + } + + if (!ValidateAddressMode(pDesc->AddressU) + || !ValidateAddressMode(pDesc->AddressV) + || !ValidateAddressMode(pDesc->AddressW)) + return E_INVALIDARG; + + // Clear BorderColor to 0 if none of the address + // modes are D3D11_TEXTURE_ADDRESS_BORDER + if (pDesc->AddressU != D3D11_TEXTURE_ADDRESS_BORDER + && pDesc->AddressV != D3D11_TEXTURE_ADDRESS_BORDER + && pDesc->AddressW != D3D11_TEXTURE_ADDRESS_BORDER) { + for (int i = 0; i < 4; i++) + pDesc->BorderColor[i] = 0.0f; + } + + return S_OK; + } + + + bool D3D11SamplerState::ValidateAddressMode(D3D11_TEXTURE_ADDRESS_MODE Mode) { + return Mode >= D3D11_TEXTURE_ADDRESS_WRAP + && Mode <= D3D11_TEXTURE_ADDRESS_MIRROR_ONCE; + } + + + bool D3D11SamplerState::ValidateComparisonFunc(D3D11_COMPARISON_FUNC Comparison) { + return Comparison >= D3D11_COMPARISON_NEVER + && Comparison <= D3D11_COMPARISON_ALWAYS; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.h new file mode 100644 index 00000000..57fa139b --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.h @@ -0,0 +1,58 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_sampler.h" + +#include "d3d11_device_child.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11SamplerState : public D3D11StateObject<ID3D11SamplerState> { + + public: + + using DescType = D3D11_SAMPLER_DESC; + + D3D11SamplerState( + D3D11Device* device, + const D3D11_SAMPLER_DESC& desc); + ~D3D11SamplerState(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void STDMETHODCALLTYPE GetDesc( + D3D11_SAMPLER_DESC* pDesc) final; + + Rc<DxvkSampler> GetDXVKSampler() const { + return m_sampler; + } + + D3D10SamplerState* GetD3D10Iface() { + return &m_d3d10; + } + + static HRESULT NormalizeDesc( + D3D11_SAMPLER_DESC* pDesc); + + private: + + D3D11_SAMPLER_DESC m_desc; + Rc<DxvkSampler> m_sampler; + D3D10SamplerState m_d3d10; + + std::atomic<uint32_t> m_refCount = { 0u }; + + static bool ValidateAddressMode( + D3D11_TEXTURE_ADDRESS_MODE Mode); + + static bool ValidateComparisonFunc( + D3D11_COMPARISON_FUNC Comparison); + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.cpp new file mode 100644 index 00000000..056044dd --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.cpp @@ -0,0 +1,140 @@ +#include "d3d11_device.h" +#include "d3d11_shader.h" + +namespace dxvk { + + D3D11CommonShader:: D3D11CommonShader() { } + D3D11CommonShader::~D3D11CommonShader() { } + + + D3D11CommonShader::D3D11CommonShader( + D3D11Device* pDevice, + const DxvkShaderKey* pShaderKey, + const DxbcModuleInfo* pDxbcModuleInfo, + const void* pShaderBytecode, + size_t BytecodeLength) { + const std::string name = pShaderKey->toString(); + Logger::debug(str::format("Compiling shader ", name)); + + DxbcReader reader( + reinterpret_cast<const char*>(pShaderBytecode), + BytecodeLength); + + DxbcModule module(reader); + + // If requested by the user, dump both the raw DXBC + // shader and the compiled SPIR-V module to a file. + const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH"); + + if (dumpPath.size() != 0) { +#ifdef _WIN32 + reader.store(std::ofstream(str::tows(str::format(dumpPath, "/", name, ".dxbc").c_str()).c_str(), + std::ios_base::binary | std::ios_base::trunc)); +#else + reader.store(std::ofstream(str::format(dumpPath, "/", name, ".dxbc").c_str(), + std::ios_base::binary | std::ios_base::trunc)); +#endif + } + + // Decide whether we need to create a pass-through + // geometry shader for vertex shader stream output + bool passthroughShader = pDxbcModuleInfo->xfb != nullptr + && (module.programInfo().type() == DxbcProgramType::VertexShader + || module.programInfo().type() == DxbcProgramType::DomainShader); + + if (module.programInfo().shaderStage() != pShaderKey->type() && !passthroughShader) + throw DxvkError("Mismatching shader type."); + + m_shader = passthroughShader + ? module.compilePassthroughShader(*pDxbcModuleInfo, name) + : module.compile (*pDxbcModuleInfo, name); + m_shader->setShaderKey(*pShaderKey); + + if (dumpPath.size() != 0) { +#ifdef _WIN32 + std::ofstream dumpStream( + str::tows(str::format(dumpPath, "/", name, ".spv").c_str()).c_str(), + std::ios_base::binary | std::ios_base::trunc); +#else + std::ofstream dumpStream( + str::format(dumpPath, "/", name, ".spv").c_str(), + std::ios_base::binary | std::ios_base::trunc); +#endif + + m_shader->dump(dumpStream); + } + + // Create shader constant buffer if necessary + if (m_shader->shaderConstants().data() != nullptr) { + DxvkBufferCreateInfo info; + info.size = m_shader->shaderConstants().sizeInBytes(); + info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + info.stages = util::pipelineStages(m_shader->stage()); + info.access = VK_ACCESS_UNIFORM_READ_BIT; + + VkMemoryPropertyFlags memFlags + = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT + | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + m_buffer = pDevice->GetDXVKDevice()->createBuffer(info, memFlags); + + std::memcpy(m_buffer->mapPtr(0), + m_shader->shaderConstants().data(), + m_shader->shaderConstants().sizeInBytes()); + } + + pDevice->GetDXVKDevice()->registerShader(m_shader); + } + + + D3D11ShaderModuleSet:: D3D11ShaderModuleSet() { } + D3D11ShaderModuleSet::~D3D11ShaderModuleSet() { } + + + HRESULT D3D11ShaderModuleSet::GetShaderModule( + D3D11Device* pDevice, + const DxvkShaderKey* pShaderKey, + const DxbcModuleInfo* pDxbcModuleInfo, + const void* pShaderBytecode, + size_t BytecodeLength, + D3D11CommonShader* pShader) { + // Use the shader's unique key for the lookup + { std::unique_lock<dxvk::mutex> lock(m_mutex); + + auto entry = m_modules.find(*pShaderKey); + if (entry != m_modules.end()) { + *pShader = entry->second; + return S_OK; + } + } + + // This shader has not been compiled yet, so we have to create a + // new module. This takes a while, so we won't lock the structure. + D3D11CommonShader module; + + try { + module = D3D11CommonShader(pDevice, pShaderKey, + pDxbcModuleInfo, pShaderBytecode, BytecodeLength); + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + + // Insert the new module into the lookup table. If another thread + // has compiled the same shader in the meantime, we should return + // that object instead and discard the newly created module. + { std::unique_lock<dxvk::mutex> lock(m_mutex); + + auto status = m_modules.insert({ *pShaderKey, module }); + if (!status.second) { + *pShader = status.first->second; + return S_OK; + } + } + + *pShader = std::move(module); + return S_OK; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.h new file mode 100644 index 00000000..3ab16854 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.h @@ -0,0 +1,158 @@ +#pragma once + +#include <mutex> +#include <unordered_map> + +#include "../dxbc/dxbc_module.h" +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_shader.h" + +#include "../util/sha1/sha1_util.h" + +#include "../util/util_env.h" + +#include "d3d11_device_child.h" +#include "d3d11_interfaces.h" + +namespace dxvk { + + class D3D11Device; + + /** + * \brief Common shader object + * + * Stores the compiled SPIR-V shader and the SHA-1 + * hash of the original DXBC shader, which can be + * used to identify the shader. + */ + class D3D11CommonShader { + + public: + + D3D11CommonShader(); + D3D11CommonShader( + D3D11Device* pDevice, + const DxvkShaderKey* pShaderKey, + const DxbcModuleInfo* pDxbcModuleInfo, + const void* pShaderBytecode, + size_t BytecodeLength); + ~D3D11CommonShader(); + + Rc<DxvkShader> GetShader() const { + return m_shader; + } + + Rc<DxvkBuffer> GetIcb() const { + return m_buffer; + } + + std::string GetName() const { + return m_shader->debugName(); + } + + private: + + Rc<DxvkShader> m_shader; + Rc<DxvkBuffer> m_buffer; + + }; + + + /** + * \brief Common shader interface + * + * Implements methods for all D3D11*Shader + * interfaces and stores the actual shader + * module object. + */ + template<typename D3D11Interface, typename D3D10Interface> + class D3D11Shader : public D3D11DeviceChild<D3D11Interface> { + using D3D10ShaderClass = D3D10Shader<D3D10Interface, D3D11Interface>; + public: + + D3D11Shader(D3D11Device* device, const D3D11CommonShader& shader) + : D3D11DeviceChild<D3D11Interface>(device), + m_shader(shader), m_d3d10(this) { } + + ~D3D11Shader() { } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final { + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(D3D11Interface)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(D3D10Interface)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + Logger::warn("D3D11Shader::QueryInterface: Unknown interface query"); + return E_NOINTERFACE; + } + + const D3D11CommonShader* GetCommonShader() const { + return &m_shader; + } + + D3D10ShaderClass* GetD3D10Iface() { + return &m_d3d10; + } + + private: + + D3D11CommonShader m_shader; + D3D10ShaderClass m_d3d10; + + }; + + using D3D11VertexShader = D3D11Shader<ID3D11VertexShader, ID3D10VertexShader>; + using D3D11HullShader = D3D11Shader<ID3D11HullShader, ID3D10DeviceChild>; + using D3D11DomainShader = D3D11Shader<ID3D11DomainShader, ID3D10DeviceChild>; + using D3D11GeometryShader = D3D11Shader<ID3D11GeometryShader, ID3D10GeometryShader>; + using D3D11PixelShader = D3D11Shader<ID3D11PixelShader, ID3D10PixelShader>; + using D3D11ComputeShader = D3D11Shader<ID3D11ComputeShader, ID3D10DeviceChild>; + + + /** + * \brief Shader module set + * + * Some applications may compile the same shader multiple + * times, so we should cache the resulting shader modules + * and reuse them rather than creating new ones. This + * class is thread-safe. + */ + class D3D11ShaderModuleSet { + + public: + + D3D11ShaderModuleSet(); + ~D3D11ShaderModuleSet(); + + HRESULT GetShaderModule( + D3D11Device* pDevice, + const DxvkShaderKey* pShaderKey, + const DxbcModuleInfo* pDxbcModuleInfo, + const void* pShaderBytecode, + size_t BytecodeLength, + D3D11CommonShader* pShader); + + private: + + dxvk::mutex m_mutex; + + std::unordered_map< + DxvkShaderKey, + D3D11CommonShader, + DxvkHash, DxvkEq> m_modules; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.cpp new file mode 100644 index 00000000..161566c0 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.cpp @@ -0,0 +1,199 @@ +#include "d3d11_state.h" + +namespace dxvk { + + size_t D3D11StateDescHash::operator () ( + const D3D11_BLEND_DESC1& 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); + hash.add(desc.StencilPassOp); + hash.add(desc.StencilFailOp); + return hash; + } + + + size_t D3D11StateDescHash::operator () ( + const D3D11_DEPTH_STENCIL_DESC& desc) const { + DxvkHashState hash; + hash.add(desc.DepthEnable); + hash.add(desc.DepthWriteMask); + hash.add(desc.DepthFunc); + hash.add(desc.StencilEnable); + hash.add(desc.StencilReadMask); + hash.add(desc.StencilWriteMask); + hash.add(this->operator () (desc.FrontFace)); + hash.add(this->operator () (desc.BackFace)); + return hash; + } + + + size_t D3D11StateDescHash::operator () ( + const D3D11_RASTERIZER_DESC2& desc) const { + std::hash<float> fhash; + + DxvkHashState hash; + hash.add(desc.FillMode); + hash.add(desc.CullMode); + hash.add(desc.FrontCounterClockwise); + hash.add(desc.DepthBias); + hash.add(fhash(desc.SlopeScaledDepthBias)); + hash.add(fhash(desc.DepthBiasClamp)); + hash.add(desc.DepthClipEnable); + hash.add(desc.ScissorEnable); + hash.add(desc.MultisampleEnable); + hash.add(desc.AntialiasedLineEnable); + hash.add(desc.ForcedSampleCount); + hash.add(desc.ConservativeRaster); + return hash; + } + + + size_t D3D11StateDescHash::operator () ( + 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; + } + + + size_t D3D11StateDescHash::operator () ( + const D3D11_SAMPLER_DESC& desc) const { + std::hash<float> fhash; + + DxvkHashState hash; + hash.add(desc.Filter); + hash.add(desc.AddressU); + hash.add(desc.AddressV); + hash.add(desc.AddressW); + hash.add(fhash(desc.MipLODBias)); + hash.add(desc.MaxAnisotropy); + hash.add(desc.ComparisonFunc); + for (uint32_t i = 0; i < 4; i++) + hash.add(fhash(desc.BorderColor[i])); + hash.add(fhash(desc.MinLOD)); + hash.add(fhash(desc.MaxLOD)); + return hash; + } + + + bool D3D11StateDescEqual::operator () ( + const D3D11_BLEND_DESC1& a, + const D3D11_BLEND_DESC1& 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 + && a.StencilFailOp == b.StencilFailOp; + } + + + 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 + && a.StencilEnable == b.StencilEnable + && a.StencilReadMask == b.StencilReadMask + && a.StencilWriteMask == b.StencilWriteMask + && this->operator () (a.FrontFace, b.FrontFace) + && this->operator () (a.BackFace, b.BackFace); + } + + + bool D3D11StateDescEqual::operator () ( + const D3D11_RASTERIZER_DESC2& a, + const D3D11_RASTERIZER_DESC2& b) const { + return a.FillMode == b.FillMode + && a.CullMode == b.CullMode + && a.FrontCounterClockwise == b.FrontCounterClockwise + && a.DepthBias == b.DepthBias + && a.SlopeScaledDepthBias == b.SlopeScaledDepthBias + && a.DepthBiasClamp == b.DepthBiasClamp + && a.DepthClipEnable == b.DepthClipEnable + && a.ScissorEnable == b.ScissorEnable + && a.MultisampleEnable == b.MultisampleEnable + && a.AntialiasedLineEnable == b.AntialiasedLineEnable + && a.ForcedSampleCount == b.ForcedSampleCount + && a.ConservativeRaster == b.ConservativeRaster; + } + + + bool D3D11StateDescEqual::operator () ( + 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; + } + + + bool D3D11StateDescEqual::operator () ( + const D3D11_SAMPLER_DESC& a, + const D3D11_SAMPLER_DESC& b) const { + return a.Filter == b.Filter + && a.AddressU == b.AddressU + && a.AddressV == b.AddressV + && a.AddressW == b.AddressW + && a.MipLODBias == b.MipLODBias + && a.MaxAnisotropy == b.MaxAnisotropy + && a.ComparisonFunc == b.ComparisonFunc + && a.BorderColor[0] == b.BorderColor[0] + && a.BorderColor[1] == b.BorderColor[1] + && a.BorderColor[2] == b.BorderColor[2] + && a.BorderColor[3] == b.BorderColor[3] + && a.MinLOD == b.MinLOD + && a.MaxLOD == b.MaxLOD; + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.h new file mode 100644 index 00000000..e807d1ad --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.h @@ -0,0 +1,79 @@ +#pragma once + +#include <unordered_map> + +#include "d3d11_blend.h" +#include "d3d11_depth_stencil.h" +#include "d3d11_rasterizer.h" +#include "d3d11_sampler.h" + +namespace dxvk { + + class D3D11Device; + + struct D3D11StateDescHash { + 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_DESC2& 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_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_DESC2& a, const D3D11_RASTERIZER_DESC2& 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; + }; + + + /** + * \brief Unique state object set + * + * When creating state objects, D3D11 first checks if + * an object with the same description already exists + * and returns it if that is the case. This class + * implements that behaviour. + */ + template<typename T> + class D3D11StateObjectSet { + using DescType = typename T::DescType; + public: + + /** + * \brief Retrieves a state object + * + * Returns an object with the same description or + * creates a new one if no such object exists. + * \param [in] device The calling D3D11 device + * \param [in] desc State object description + * \returns Pointer to the state object + */ + T* Create(D3D11Device* device, const DescType& desc) { + std::lock_guard<dxvk::mutex> lock(m_mutex); + + auto entry = m_objects.find(desc); + + if (entry != m_objects.end()) + return ref(&entry->second); + + auto result = m_objects.emplace( + std::piecewise_construct, + std::tuple(desc), + std::tuple(device, desc)); + return ref(&result.first->second); + } + + private: + + dxvk::mutex m_mutex; + std::unordered_map<DescType, T, + D3D11StateDescHash, D3D11StateDescEqual> m_objects; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.cpp new file mode 100644 index 00000000..33cc8a33 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.cpp @@ -0,0 +1,37 @@ +#include "d3d11_state_object.h" + +namespace dxvk { + + D3D11DeviceContextState::D3D11DeviceContextState( + D3D11Device* pDevice) + : D3D11DeviceChild<ID3DDeviceContextState>(pDevice) { + + } + + + D3D11DeviceContextState::~D3D11DeviceContextState() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11DeviceContextState::QueryInterface( + REFIID riid, + void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3DDeviceContextState)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11DeviceContextState::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.h new file mode 100644 index 00000000..775a0951 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.h @@ -0,0 +1,44 @@ +#pragma once + +#include "d3d11_device.h" +#include "d3d11_context_state.h" +#include "d3d11_device_child.h" + +namespace dxvk { + + /** + * \brief Device context state implementation + * + * This is an opaque interface in D3D11, and we only + * implement the state block-like functionality, not + * the methods to disable certain context and device + * interfaces based on the emulated device IID. + */ + class D3D11DeviceContextState : public D3D11DeviceChild<ID3DDeviceContextState> { + + public: + + D3D11DeviceContextState( + D3D11Device* pDevice); + + ~D3D11DeviceContextState(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void SetState(const D3D11ContextState& State) { + m_state = State; + } + + void GetState(D3D11ContextState& State) const { + State = m_state; + } + + private: + + D3D11ContextState m_state; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.cpp new file mode 100644 index 00000000..d7483593 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.cpp @@ -0,0 +1,681 @@ +#include "d3d11_context_imm.h" +#include "d3d11_device.h" +#include "d3d11_swapchain.h" + +namespace dxvk { + + static uint16_t MapGammaControlPoint(float x) { + if (x < 0.0f) x = 0.0f; + if (x > 1.0f) x = 1.0f; + return uint16_t(65535.0f * x); + } + + + D3D11SwapChain::D3D11SwapChain( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice, + HWND hWnd, + const DXGI_SWAP_CHAIN_DESC1* pDesc) + : m_dxgiDevice(pContainer), + m_parent (pDevice), + m_window (hWnd), + m_desc (*pDesc), + m_device (pDevice->GetDXVKDevice()), + m_context (m_device->createContext()), + m_frameLatencyCap(pDevice->GetOptions()->maxFrameLatency) { + CreateFrameLatencyEvent(); + + if (!pDevice->GetOptions()->deferSurfaceCreation) + CreatePresenter(); + + CreateBackBuffer(); + CreateBlitter(); + CreateHud(); + } + + + D3D11SwapChain::~D3D11SwapChain() { + m_device->waitForSubmission(&m_presentStatus); + m_device->waitForIdle(); + + if (m_backBuffer) + m_backBuffer->ReleasePrivate(); + + DestroyFrameLatencyEvent(); + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::QueryInterface( + REFIID riid, + void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + InitReturnPtr(ppvObject); + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(IDXGIVkSwapChain)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11SwapChain::QueryInterface: Unknown interface query"); + return E_NOINTERFACE; + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::GetDesc( + DXGI_SWAP_CHAIN_DESC1* pDesc) { + *pDesc = m_desc; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::GetAdapter( + REFIID riid, + void** ppvObject) { + return m_dxgiDevice->GetParent(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::GetDevice( + REFIID riid, + void** ppDevice) { + return m_dxgiDevice->QueryInterface(riid, ppDevice); + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::GetImage( + UINT BufferId, + REFIID riid, + void** ppBuffer) { + InitReturnPtr(ppBuffer); + + if (BufferId > 0) { + Logger::err("D3D11: GetImage: BufferId > 0 not supported"); + return DXGI_ERROR_UNSUPPORTED; + } + + return m_backBuffer->QueryInterface(riid, ppBuffer); + } + + + UINT STDMETHODCALLTYPE D3D11SwapChain::GetImageIndex() { + return 0; + } + + + UINT STDMETHODCALLTYPE D3D11SwapChain::GetFrameLatency() { + return m_frameLatency; + } + + + HANDLE STDMETHODCALLTYPE D3D11SwapChain::GetFrameLatencyEvent() { + return m_frameLatencyEvent; + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::ChangeProperties( + const DXGI_SWAP_CHAIN_DESC1* pDesc) { + + m_dirty |= m_desc.Format != pDesc->Format + || m_desc.Width != pDesc->Width + || m_desc.Height != pDesc->Height + || m_desc.BufferCount != pDesc->BufferCount + || m_desc.Flags != pDesc->Flags; + + m_desc = *pDesc; + CreateBackBuffer(); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetPresentRegion( + const RECT* pRegion) { + // TODO implement + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetGammaControl( + UINT NumControlPoints, + const DXGI_RGB* pControlPoints) { + bool isIdentity = true; + + if (NumControlPoints > 1) { + std::array<DxvkGammaCp, 1025> cp; + + if (NumControlPoints > cp.size()) + return E_INVALIDARG; + + for (uint32_t i = 0; i < NumControlPoints; i++) { + uint16_t identity = MapGammaControlPoint(float(i) / float(NumControlPoints - 1)); + + cp[i].r = MapGammaControlPoint(pControlPoints[i].Red); + cp[i].g = MapGammaControlPoint(pControlPoints[i].Green); + cp[i].b = MapGammaControlPoint(pControlPoints[i].Blue); + cp[i].a = 0; + + isIdentity &= cp[i].r == identity + && cp[i].g == identity + && cp[i].b == identity; + } + + if (!isIdentity) + m_blitter->setGammaRamp(NumControlPoints, cp.data()); + } + + if (isIdentity) + m_blitter->setGammaRamp(0, nullptr); + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetFrameLatency( + UINT MaxLatency) { + if (MaxLatency == 0 || MaxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS) + return DXGI_ERROR_INVALID_CALL; + +#ifdef _WIN32 + if (m_frameLatencyEvent) { + // Windows DXGI does not seem to handle the case where the new maximum + // latency is less than the current value, and some games relying on + // this behaviour will hang if we attempt to decrement the semaphore. + // Thus, only increment the semaphore as necessary. + if (MaxLatency > m_frameLatency) + ReleaseSemaphore(m_frameLatencyEvent, MaxLatency - m_frameLatency, nullptr); + } +#endif + + m_frameLatency = MaxLatency; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11SwapChain::Present( + UINT SyncInterval, + UINT PresentFlags, + const DXGI_PRESENT_PARAMETERS* pPresentParameters) { + auto options = m_parent->GetOptions(); + + if (options->syncInterval >= 0) + SyncInterval = options->syncInterval; + + if (!(PresentFlags & DXGI_PRESENT_TEST)) { + bool vsync = SyncInterval != 0; + + m_dirty |= vsync != m_vsync; + m_vsync = vsync; + } + + if (m_presenter == nullptr) + CreatePresenter(); + + HRESULT hr = S_OK; + + if (!m_presenter->hasSwapChain()) { + RecreateSwapChain(m_vsync); + m_dirty = false; + } + + if (!m_presenter->hasSwapChain()) + hr = DXGI_STATUS_OCCLUDED; + + if (m_device->getDeviceStatus() != VK_SUCCESS) + hr = DXGI_ERROR_DEVICE_RESET; + + if ((PresentFlags & DXGI_PRESENT_TEST) || hr != S_OK) + return hr; + + if (std::exchange(m_dirty, false)) + RecreateSwapChain(m_vsync); + + try { + PresentImage(SyncInterval); + } catch (const DxvkError& e) { + Logger::err(e.message()); + hr = E_FAIL; + } + + return hr; + } + + + void STDMETHODCALLTYPE D3D11SwapChain::NotifyModeChange( + BOOL Windowed, + const DXGI_MODE_DESC* pDisplayMode) { + if (Windowed || !pDisplayMode) { + // Display modes aren't meaningful in windowed mode + m_displayRefreshRate = 0.0; + } else { + DXGI_RATIONAL rate = pDisplayMode->RefreshRate; + m_displayRefreshRate = double(rate.Numerator) / double(rate.Denominator); + } + + if (m_presenter != nullptr) + m_presenter->setFrameRateLimiterRefreshRate(m_displayRefreshRate); + } + + + HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) { + Com<ID3D11DeviceContext> deviceContext = nullptr; + m_parent->GetImmediateContext(&deviceContext); + + // Flush pending rendering commands before + auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr()); + immediateContext->Flush(); + + // Bump our frame id. + ++m_frameId; + + for (uint32_t i = 0; i < SyncInterval || i < 1; i++) { + SynchronizePresent(); + + if (!m_presenter->hasSwapChain()) + return DXGI_STATUS_OCCLUDED; + + // Presentation semaphores and WSI swap chain image + vk::PresenterInfo info = m_presenter->info(); + vk::PresenterSync sync; + + uint32_t imageIndex = 0; + + VkResult status = m_presenter->acquireNextImage(sync, imageIndex); + + while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) { + RecreateSwapChain(m_vsync); + + if (!m_presenter->hasSwapChain()) + return DXGI_STATUS_OCCLUDED; + + info = m_presenter->info(); + status = m_presenter->acquireNextImage(sync, imageIndex); + } + + // Resolve back buffer if it is multisampled. We + // only have to do it only for the first frame. + m_context->beginRecording( + m_device->createCommandList()); + + m_blitter->presentImage(m_context.ptr(), + m_imageViews.at(imageIndex), VkRect2D(), + m_swapImageView, VkRect2D()); + + if (m_hud != nullptr) + m_hud->render(m_context, info.format, info.imageExtent); + + if (i + 1 >= SyncInterval) + m_context->signal(m_frameLatencySignal, m_frameId); + + SubmitPresent(immediateContext, sync, i); + } + + SyncFrameLatency(); + return S_OK; + } + + + void D3D11SwapChain::SubmitPresent( + D3D11ImmediateContext* pContext, + const vk::PresenterSync& Sync, + uint32_t FrameId) { + auto lock = pContext->LockContext(); + + // Present from CS thread so that we don't + // have to synchronize with it first. + m_presentStatus.result = VK_NOT_READY; + + pContext->EmitCs([this, + cFrameId = FrameId, + cSync = Sync, + cHud = m_hud, + cCommandList = m_context->endRecording() + ] (DxvkContext* ctx) { + m_device->submitCommandList(cCommandList, + cSync.acquire, cSync.present); + + if (cHud != nullptr && !cFrameId) + cHud->update(); + + m_device->presentImage(m_presenter, &m_presentStatus); + }); + + pContext->FlushCsChunk(); + } + + + void D3D11SwapChain::SynchronizePresent() { + // Recreate swap chain if the previous present call failed + VkResult status = m_device->waitForSubmission(&m_presentStatus); + + if (status != VK_SUCCESS) + RecreateSwapChain(m_vsync); + } + + + void D3D11SwapChain::RecreateSwapChain(BOOL Vsync) { + // Ensure that we can safely destroy the swap chain + m_device->waitForSubmission(&m_presentStatus); + m_device->waitForIdle(); + + m_presentStatus.result = VK_SUCCESS; + + vk::PresenterDesc presenterDesc; + presenterDesc.imageExtent = { m_desc.Width, m_desc.Height }; + presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1); + presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats); + presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes); + presenterDesc.fullScreenExclusive = PickFullscreenMode(); + + if (m_presenter->recreateSwapChain(presenterDesc) != VK_SUCCESS) + throw DxvkError("D3D11SwapChain: Failed to recreate swap chain"); + + CreateRenderTargetViews(); + } + + + void D3D11SwapChain::CreateFrameLatencyEvent() { + m_frameLatencySignal = new sync::CallbackFence(m_frameId); + + if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) { +#ifndef DXVK_NATIVE + m_frameLatencyEvent = CreateEvent(nullptr, false, true, nullptr); +#else + throw DxvkError("DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT not supported on this platform."); +#endif + } + } + + + void D3D11SwapChain::CreatePresenter() { + DxvkDeviceQueue graphicsQueue = m_device->queues().graphics; + + vk::PresenterDevice presenterDevice; + presenterDevice.queueFamily = graphicsQueue.queueFamily; + presenterDevice.queue = graphicsQueue.queueHandle; + presenterDevice.adapter = m_device->adapter()->handle(); + presenterDevice.features.fullScreenExclusive = m_device->extensions().extFullScreenExclusive; + + vk::PresenterDesc presenterDesc; + presenterDesc.imageExtent = { m_desc.Width, m_desc.Height }; + presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1); + presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats); + presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes); + presenterDesc.fullScreenExclusive = PickFullscreenMode(); + + m_presenter = new vk::Presenter(m_window, + m_device->adapter()->vki(), + m_device->vkd(), + presenterDevice, + presenterDesc); + + m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate); + m_presenter->setFrameRateLimiterRefreshRate(m_displayRefreshRate); + + CreateRenderTargetViews(); + } + + + void D3D11SwapChain::CreateRenderTargetViews() { + vk::PresenterInfo info = m_presenter->info(); + + m_imageViews.clear(); + m_imageViews.resize(info.imageCount); + + DxvkImageCreateInfo imageInfo; + imageInfo.type = VK_IMAGE_TYPE_2D; + imageInfo.format = info.format.format; + imageInfo.flags = 0; + imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT; + imageInfo.extent = { info.imageExtent.width, info.imageExtent.height, 1 }; + imageInfo.numLayers = 1; + imageInfo.mipLevels = 1; + imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageInfo.stages = 0; + imageInfo.access = 0; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + imageInfo.shared = VK_TRUE; + + DxvkImageViewCreateInfo viewInfo; + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = info.format.format; + viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + + for (uint32_t i = 0; i < info.imageCount; i++) { + VkImage imageHandle = m_presenter->getImage(i).image; + + Rc<DxvkImage> image = new DxvkImage( + m_device->vkd(), imageInfo, imageHandle); + + m_imageViews[i] = new DxvkImageView( + m_device->vkd(), image, viewInfo); + } + } + + + void D3D11SwapChain::CreateBackBuffer() { + // Explicitly destroy current swap image before + // creating a new one to free up resources + if (m_backBuffer) + m_backBuffer->ReleasePrivate(); + + m_swapImage = nullptr; + m_swapImageView = nullptr; + m_backBuffer = nullptr; + + // Create new back buffer + D3D11_COMMON_TEXTURE_DESC desc; + desc.Width = std::max(m_desc.Width, 1u); + desc.Height = std::max(m_desc.Height, 1u); + desc.Depth = 1; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = m_desc.Format; + desc.SampleDesc = m_desc.SampleDesc; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = 0; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED; + + if (m_desc.BufferUsage & DXGI_USAGE_RENDER_TARGET_OUTPUT) + desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + + if (m_desc.BufferUsage & DXGI_USAGE_SHADER_INPUT) + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + + if (m_desc.BufferUsage & DXGI_USAGE_UNORDERED_ACCESS) + desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + + if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) + desc.MiscFlags |= D3D11_RESOURCE_MISC_GDI_COMPATIBLE; + + DXGI_USAGE dxgiUsage = DXGI_USAGE_BACK_BUFFER; + + if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD + || m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD) + dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT; + + m_backBuffer = new D3D11Texture2D(m_parent, &desc, dxgiUsage, VK_NULL_HANDLE); + m_backBuffer->AddRefPrivate(); + + m_swapImage = GetCommonTexture(m_backBuffer)->GetImage(); + + // Create an image view that allows the + // image to be bound as a shader resource. + DxvkImageViewCreateInfo viewInfo; + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = m_swapImage->info().format; + viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + m_swapImageView = m_device->createImageView(m_swapImage, viewInfo); + + // Initialize the image so that we can use it. Clearing + // to black prevents garbled output for the first frame. + VkImageSubresourceRange subresources; + subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresources.baseMipLevel = 0; + subresources.levelCount = 1; + subresources.baseArrayLayer = 0; + subresources.layerCount = 1; + + VkClearColorValue clearColor; + clearColor.float32[0] = 0.0f; + clearColor.float32[1] = 0.0f; + clearColor.float32[2] = 0.0f; + clearColor.float32[3] = 0.0f; + + m_context->beginRecording( + m_device->createCommandList()); + + m_context->clearColorImage( + m_swapImage, clearColor, subresources); + + m_device->submitCommandList( + m_context->endRecording(), + VK_NULL_HANDLE, + VK_NULL_HANDLE); + } + + + void D3D11SwapChain::CreateBlitter() { + m_blitter = new DxvkSwapchainBlitter(m_device); + } + + + void D3D11SwapChain::CreateHud() { + m_hud = hud::Hud::createHud(m_device); + + if (m_hud != nullptr) + m_hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName()); + } + + + void D3D11SwapChain::DestroyFrameLatencyEvent() { +#ifndef DXVK_NATIVE + CloseHandle(m_frameLatencyEvent); +#endif + } + + + void D3D11SwapChain::SyncFrameLatency() { + // Wait for the sync event so that we respect the maximum frame latency + m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency()); + +#ifndef DXVK_NATIVE + if (m_frameLatencyEvent) { + m_frameLatencySignal->setCallback(m_frameId, [cFrameLatencyEvent = m_frameLatencyEvent] () { + ReleaseSemaphore(cFrameLatencyEvent, 1, nullptr); + }); + } +#endif + } + + + uint32_t D3D11SwapChain::GetActualFrameLatency() { + uint32_t maxFrameLatency = m_frameLatency; + + if (!(m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)) + m_dxgiDevice->GetMaximumFrameLatency(&maxFrameLatency); + + if (m_frameLatencyCap) + maxFrameLatency = std::min(maxFrameLatency, m_frameLatencyCap); + + maxFrameLatency = std::min(maxFrameLatency, m_desc.BufferCount + 1); + return maxFrameLatency; + } + + + uint32_t D3D11SwapChain::PickFormats( + DXGI_FORMAT Format, + VkSurfaceFormatKHR* pDstFormats) { + uint32_t n = 0; + + switch (Format) { + default: + Logger::warn(str::format("D3D11SwapChain: Unexpected format: ", m_desc.Format)); + + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: { + pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + } break; + + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: { + pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + } break; + + case DXGI_FORMAT_R10G10B10A2_UNORM: { + pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + } break; + + case DXGI_FORMAT_R16G16B16A16_FLOAT: { + pDstFormats[n++] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + } break; + } + + return n; + } + + + uint32_t D3D11SwapChain::PickPresentModes( + BOOL Vsync, + VkPresentModeKHR* pDstModes) { + uint32_t n = 0; + + if (Vsync) { + if (m_parent->GetOptions()->tearFree == Tristate::False) + pDstModes[n++] = VK_PRESENT_MODE_FIFO_RELAXED_KHR; + pDstModes[n++] = VK_PRESENT_MODE_FIFO_KHR; + } else { + if (m_parent->GetOptions()->tearFree != Tristate::True) + pDstModes[n++] = VK_PRESENT_MODE_IMMEDIATE_KHR; + pDstModes[n++] = VK_PRESENT_MODE_MAILBOX_KHR; + } + + return n; + } + + + uint32_t D3D11SwapChain::PickImageCount( + UINT Preferred) { + int32_t option = m_parent->GetOptions()->numBackBuffers; + return option > 0 ? uint32_t(option) : uint32_t(Preferred); + } + + + VkFullScreenExclusiveEXT D3D11SwapChain::PickFullscreenMode() { + return m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH + ? VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT + : VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT; + } + + + std::string D3D11SwapChain::GetApiName() const { + Com<IDXGIDXVKDevice> device; + m_parent->QueryInterface(__uuidof(IDXGIDXVKDevice), reinterpret_cast<void**>(&device)); + + uint32_t apiVersion = device->GetAPIVersion(); + uint32_t featureLevel = m_parent->GetFeatureLevel(); + + uint32_t flHi = (featureLevel >> 12); + uint32_t flLo = (featureLevel >> 8) & 0x7; + + return str::format("D3D", apiVersion, " FL", flHi, "_", flLo); + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.h new file mode 100644 index 00000000..8fc9fe10 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.h @@ -0,0 +1,164 @@ +#pragma once + +#include "d3d11_texture.h" + +#include "../dxvk/hud/dxvk_hud.h" + +#include "../dxvk/dxvk_swapchain_blitter.h" + +#include "../util/sync/sync_signal.h" + +namespace dxvk { + + class D3D11Device; + class D3D11DXGIDevice; + + class D3D11SwapChain : public ComObject<IDXGIVkSwapChain> { + constexpr static uint32_t DefaultFrameLatency = 1; + public: + + D3D11SwapChain( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice, + HWND hWnd, + const DXGI_SWAP_CHAIN_DESC1* pDesc); + + ~D3D11SwapChain(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE GetDesc( + DXGI_SWAP_CHAIN_DESC1* pDesc); + + HRESULT STDMETHODCALLTYPE GetAdapter( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE GetDevice( + REFIID riid, + void** ppDevice); + + HRESULT STDMETHODCALLTYPE GetImage( + UINT BufferId, + REFIID riid, + void** ppBuffer); + + UINT STDMETHODCALLTYPE GetImageIndex(); + + UINT STDMETHODCALLTYPE GetFrameLatency(); + + HANDLE STDMETHODCALLTYPE GetFrameLatencyEvent(); + + HRESULT STDMETHODCALLTYPE ChangeProperties( + const DXGI_SWAP_CHAIN_DESC1* pDesc); + + HRESULT STDMETHODCALLTYPE SetPresentRegion( + const RECT* pRegion); + + HRESULT STDMETHODCALLTYPE SetGammaControl( + UINT NumControlPoints, + const DXGI_RGB* pControlPoints); + + HRESULT STDMETHODCALLTYPE SetFrameLatency( + UINT MaxLatency); + + HRESULT STDMETHODCALLTYPE Present( + UINT SyncInterval, + UINT PresentFlags, + const DXGI_PRESENT_PARAMETERS* pPresentParameters); + + void STDMETHODCALLTYPE NotifyModeChange( + BOOL Windowed, + const DXGI_MODE_DESC* pDisplayMode); + + private: + + enum BindingIds : uint32_t { + Image = 0, + Gamma = 1, + }; + + Com<D3D11DXGIDevice, false> m_dxgiDevice; + + D3D11Device* m_parent; + HWND m_window; + + DXGI_SWAP_CHAIN_DESC1 m_desc; + + Rc<DxvkDevice> m_device; + Rc<DxvkContext> m_context; + + Rc<vk::Presenter> m_presenter; + + Rc<DxvkImage> m_swapImage; + Rc<DxvkImageView> m_swapImageView; + Rc<DxvkSwapchainBlitter> m_blitter; + + Rc<hud::Hud> m_hud; + + D3D11Texture2D* m_backBuffer = nullptr; + DxvkSubmitStatus m_presentStatus; + + std::vector<Rc<DxvkImageView>> m_imageViews; + + uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS; + uint32_t m_frameLatency = DefaultFrameLatency; + uint32_t m_frameLatencyCap = 0; + HANDLE m_frameLatencyEvent = nullptr; + Rc<sync::CallbackFence> m_frameLatencySignal; + + bool m_dirty = true; + bool m_vsync = true; + + double m_displayRefreshRate = 0.0; + + HRESULT PresentImage(UINT SyncInterval); + + void SubmitPresent( + D3D11ImmediateContext* pContext, + const vk::PresenterSync& Sync, + uint32_t FrameId); + + void SynchronizePresent(); + + void RecreateSwapChain( + BOOL Vsync); + + void CreateFrameLatencyEvent(); + + void CreatePresenter(); + + void CreateRenderTargetViews(); + + void CreateBackBuffer(); + + void CreateBlitter(); + + void CreateHud(); + + void DestroyFrameLatencyEvent(); + + void SyncFrameLatency(); + + uint32_t GetActualFrameLatency(); + + uint32_t PickFormats( + DXGI_FORMAT Format, + VkSurfaceFormatKHR* pDstFormats); + + uint32_t PickPresentModes( + BOOL Vsync, + VkPresentModeKHR* pDstModes); + + uint32_t PickImageCount( + UINT Preferred); + + VkFullScreenExclusiveEXT PickFullscreenMode(); + + std::string GetApiName() const; + + }; + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.cpp new file mode 100644 index 00000000..35c6afd8 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.cpp @@ -0,0 +1,1269 @@ +#include "d3d11_device.h" +#include "d3d11_gdi.h" +#include "d3d11_texture.h" + +namespace dxvk { + + D3D11CommonTexture::D3D11CommonTexture( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc, + D3D11_RESOURCE_DIMENSION Dimension, + DXGI_USAGE DxgiUsage, + VkImage vkImage) + : m_device(pDevice), m_dimension(Dimension), m_desc(*pDesc), m_dxgiUsage(DxgiUsage) { + DXGI_VK_FORMAT_MODE formatMode = GetFormatMode(); + DXGI_VK_FORMAT_INFO formatInfo = m_device->LookupFormat(m_desc.Format, formatMode); + DXGI_VK_FORMAT_FAMILY formatFamily = m_device->LookupFamily(m_desc.Format, formatMode); + DXGI_VK_FORMAT_INFO formatPacked = m_device->LookupPackedFormat(m_desc.Format, formatMode); + m_packedFormat = formatPacked.Format; + + DxvkImageCreateInfo imageInfo; + imageInfo.type = GetVkImageType(); + imageInfo.format = formatInfo.Format; + imageInfo.flags = 0; + imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT; + imageInfo.extent.width = m_desc.Width; + imageInfo.extent.height = m_desc.Height; + imageInfo.extent.depth = m_desc.Depth; + imageInfo.numLayers = m_desc.ArraySize; + imageInfo.mipLevels = m_desc.MipLevels; + imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT; + imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_TRANSFER_WRITE_BIT; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.layout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.shared = vkImage != VK_NULL_HANDLE; + + if (!pDevice->GetOptions()->disableMsaa) + DecodeSampleCount(m_desc.SampleDesc.Count, &imageInfo.sampleCount); + + // Integer clear operations on UAVs are implemented using + // a view with a bit-compatible integer format, so we'll + // have to include that format in the format family + if (m_desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) { + DXGI_VK_FORMAT_INFO formatBase = m_device->LookupFormat( + m_desc.Format, DXGI_VK_FORMAT_MODE_RAW); + + if (formatBase.Format != formatInfo.Format + && formatBase.Format != VK_FORMAT_UNDEFINED) { + formatFamily.Add(formatBase.Format); + formatFamily.Add(formatInfo.Format); + } + } + + // The image must be marked as mutable if it can be reinterpreted + // by a view with a different format. Depth-stencil formats cannot + // be reinterpreted in Vulkan, so we'll ignore those. + auto formatProperties = imageFormatInfo(formatInfo.Format); + + bool isTypeless = formatInfo.Aspect == 0; + bool isMutable = formatFamily.FormatCount > 1; + bool isMultiPlane = (formatProperties->aspectMask & VK_IMAGE_ASPECT_PLANE_0_BIT) != 0; + bool isColorFormat = (formatProperties->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0; + + if (isMutable && (isColorFormat || isMultiPlane)) { + imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + + // Typeless UAV images have relaxed reinterpretation rules + if (!isTypeless || !(m_desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS)) { + imageInfo.viewFormatCount = formatFamily.FormatCount; + imageInfo.viewFormats = formatFamily.Formats; + } + } + + // Adjust image flags based on the corresponding D3D flags + if (m_desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) { + imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.stages |= pDevice->GetEnabledShaderStages(); + imageInfo.access |= VK_ACCESS_SHADER_READ_BIT; + } + + if (m_desc.BindFlags & D3D11_BIND_RENDER_TARGET) { + imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT + | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + } + + if (m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) { + imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT + | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + } + + if (m_desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) { + imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT; + imageInfo.stages |= pDevice->GetEnabledShaderStages(); + imageInfo.access |= VK_ACCESS_SHADER_READ_BIT + | VK_ACCESS_SHADER_WRITE_BIT; + + // UAVs are not supported for sRGB formats on most drivers, + // but we can still create linear views for the image + if (formatProperties->flags.test(DxvkFormatFlag::ColorSpaceSrgb)) + imageInfo.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; + } + + // Multi-plane formats need views to be created with color formats, and + // may not report all relevant usage flags as supported on their own. + // Also, enable sampled bit to enable use with video processor APIs. + if (isMultiPlane) { + imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT + | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; + } + + // Access pattern for meta-resolve operations + if (imageInfo.sampleCount != VK_SAMPLE_COUNT_1_BIT && isColorFormat) { + imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + imageInfo.access |= VK_ACCESS_SHADER_READ_BIT; + } + + if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) + imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + + if (Dimension == D3D11_RESOURCE_DIMENSION_TEXTURE3D && + (m_desc.BindFlags & D3D11_BIND_RENDER_TARGET)) + imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; + + // Swap chain back buffers need to be shader readable + if (DxgiUsage & DXGI_USAGE_BACK_BUFFER) { + imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + imageInfo.access |= VK_ACCESS_SHADER_READ_BIT; + imageInfo.shared = VK_TRUE; + } + + // Some image formats (i.e. the R32G32B32 ones) are + // only supported with linear tiling on most GPUs + if (!CheckImageSupport(&imageInfo, VK_IMAGE_TILING_OPTIMAL)) + imageInfo.tiling = VK_IMAGE_TILING_LINEAR; + + // Determine map mode based on our findings + m_mapMode = DetermineMapMode(&imageInfo); + + // If the image is mapped directly to host memory, we need + // to enable linear tiling, and DXVK needs to be aware that + // the image can be accessed by the host. + if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) { + imageInfo.tiling = VK_IMAGE_TILING_LINEAR; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + } + + // If necessary, create the mapped linear buffer + if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) { + for (uint32_t i = 0; i < m_desc.ArraySize; i++) { + for (uint32_t j = 0; j < m_desc.MipLevels; j++) { + if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) + m_buffers.push_back(CreateMappedBuffer(j)); + + m_mapTypes.push_back(D3D11_MAP(~0u)); + } + } + } + + // Skip image creation if possible + if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) + return; + + // We must keep LINEAR images in GENERAL layout, but we + // can choose a better layout for the image based on how + // it is going to be used by the game. + if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL && !isMultiPlane) + imageInfo.layout = OptimizeLayout(imageInfo.usage); + + // For some formats, we need to enable sampled and/or + // render target capabilities if available, but these + // should in no way affect the default image layout + imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling); + imageInfo.usage |= EnableMetaPackUsage(imageInfo.format, m_desc.CPUAccessFlags); + + // Check if we can actually create the image + if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) { + throw DxvkError(str::format( + "D3D11: Cannot create texture:", + "\n Format: ", m_desc.Format, + "\n Extent: ", m_desc.Width, + "x", m_desc.Height, + "x", m_desc.Depth, + "\n Samples: ", m_desc.SampleDesc.Count, + "\n Layers: ", m_desc.ArraySize, + "\n Levels: ", m_desc.MipLevels, + "\n Usage: ", std::hex, m_desc.BindFlags, + "\n Flags: ", std::hex, m_desc.MiscFlags)); + } + + // Create the image on a host-visible memory type + // in case it is going to be mapped directly. + VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) { + memoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + + if (vkImage == VK_NULL_HANDLE) + m_image = m_device->GetDXVKDevice()->createImage(imageInfo, memoryProperties); + else + m_image = m_device->GetDXVKDevice()->createImageFromVkImage(imageInfo, vkImage); + } + + + D3D11CommonTexture::~D3D11CommonTexture() { + + } + + + VkDeviceSize D3D11CommonTexture::ComputeMappedOffset(UINT Subresource, UINT Plane, VkOffset3D Offset) const { + auto packedFormatInfo = imageFormatInfo(m_packedFormat); + + VkImageAspectFlags aspectMask = packedFormatInfo->aspectMask; + VkDeviceSize elementSize = packedFormatInfo->elementSize; + + if (packedFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) { + auto plane = &packedFormatInfo->planes[Plane]; + elementSize = plane->elementSize; + Offset.x /= plane->blockSize.width; + Offset.y /= plane->blockSize.height; + aspectMask = vk::getPlaneAspect(Plane); + } + + auto layout = GetSubresourceLayout(aspectMask, Subresource); + auto blockOffset = util::computeBlockOffset(Offset, packedFormatInfo->blockSize); + + return VkDeviceSize(blockOffset.z) * layout.DepthPitch + + VkDeviceSize(blockOffset.y) * layout.RowPitch + + VkDeviceSize(blockOffset.x) * elementSize + + VkDeviceSize(layout.Offset); + } + + + VkImageSubresource D3D11CommonTexture::GetSubresourceFromIndex( + VkImageAspectFlags Aspect, + UINT Subresource) const { + VkImageSubresource result; + result.aspectMask = Aspect; + result.mipLevel = Subresource % m_desc.MipLevels; + result.arrayLayer = Subresource / m_desc.MipLevels; + return result; + } + + + D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT D3D11CommonTexture::GetSubresourceLayout( + VkImageAspectFlags AspectMask, + UINT Subresource) const { + VkImageSubresource subresource = GetSubresourceFromIndex(AspectMask, Subresource); + D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { }; + + switch (m_mapMode) { + case D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT: { + auto vkLayout = m_image->querySubresourceLayout(subresource); + layout.Offset = vkLayout.offset; + layout.Size = vkLayout.size; + layout.RowPitch = vkLayout.rowPitch; + layout.DepthPitch = vkLayout.depthPitch; + } break; + + case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER: + case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING: { + auto packedFormatInfo = imageFormatInfo(m_packedFormat); + + VkImageAspectFlags aspects = packedFormatInfo->aspectMask; + VkExtent3D mipExtent = MipLevelExtent(subresource.mipLevel); + + while (aspects) { + auto aspect = vk::getNextAspect(aspects); + auto extent = mipExtent; + auto elementSize = packedFormatInfo->elementSize; + + if (packedFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) { + auto plane = &packedFormatInfo->planes[vk::getPlaneIndex(aspect)]; + extent.width /= plane->blockSize.width; + extent.height /= plane->blockSize.height; + elementSize = plane->elementSize; + } + + auto blockCount = util::computeBlockCount(extent, packedFormatInfo->blockSize); + + if (!layout.RowPitch) { + layout.RowPitch = elementSize * blockCount.width; + layout.DepthPitch = elementSize * blockCount.width * blockCount.height; + } + + VkDeviceSize size = elementSize * blockCount.width * blockCount.height * blockCount.depth; + + if (aspect & AspectMask) + layout.Size += size; + else if (!layout.Size) + layout.Offset += size; + } + } break; + + case D3D11_COMMON_TEXTURE_MAP_MODE_NONE: + break; /* no op */ + } + + // D3D wants us to return the total subresource size in some instances + if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE2D) layout.RowPitch = layout.Size; + if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE3D) layout.DepthPitch = layout.Size; + return layout; + } + + + DXGI_VK_FORMAT_MODE D3D11CommonTexture::GetFormatMode() const { + if (m_desc.BindFlags & D3D11_BIND_RENDER_TARGET) + return DXGI_VK_FORMAT_MODE_COLOR; + + if (m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) + return DXGI_VK_FORMAT_MODE_DEPTH; + + return DXGI_VK_FORMAT_MODE_ANY; + } + + + uint32_t D3D11CommonTexture::GetPlaneCount() const { + return vk::getPlaneCount(m_image->formatInfo()->aspectMask); + } + + + bool D3D11CommonTexture::CheckViewCompatibility(UINT BindFlags, DXGI_FORMAT Format, UINT Plane) const { + const DxvkImageCreateInfo& imageInfo = m_image->info(); + + // Check whether the given bind flags are supported + if ((m_desc.BindFlags & BindFlags) != BindFlags) + return false; + + // Check whether the view format is compatible + DXGI_VK_FORMAT_MODE formatMode = GetFormatMode(); + DXGI_VK_FORMAT_INFO viewFormat = m_device->LookupFormat(Format, formatMode); + DXGI_VK_FORMAT_INFO baseFormat = m_device->LookupFormat(m_desc.Format, formatMode); + + // Check whether the plane index is valid for the given format + uint32_t planeCount = GetPlaneCount(); + + if (Plane >= planeCount) + return false; + + if (imageInfo.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) { + // Check whether the given combination of image + // view type and view format is actually supported + VkFormatFeatureFlags features = GetImageFormatFeatures(BindFlags); + + if (!CheckFormatFeatureSupport(viewFormat.Format, features)) + return false; + + // Using the image format itself is supported for non-planar formats + if (viewFormat.Format == baseFormat.Format && planeCount == 1) + return true; + + // If there is a list of compatible formats, the view format must be + // included in that list. For planar formats, the list is laid out in + // such a way that the n-th format is supported for the n-th plane. + for (size_t i = Plane; i < imageInfo.viewFormatCount; i += planeCount) { + if (imageInfo.viewFormats[i] == viewFormat.Format) { + return true; + } + } + + // Otherwise, all bit-compatible formats can be used. + if (imageInfo.viewFormatCount == 0 && planeCount == 1) { + auto baseFormatInfo = imageFormatInfo(baseFormat.Format); + auto viewFormatInfo = imageFormatInfo(viewFormat.Format); + + return baseFormatInfo->aspectMask == viewFormatInfo->aspectMask + && baseFormatInfo->elementSize == viewFormatInfo->elementSize; + } + + return false; + } else { + // For non-mutable images, the view format + // must be identical to the image format. + return viewFormat.Format == baseFormat.Format && planeCount == 1; + } + } + + + HRESULT D3D11CommonTexture::NormalizeTextureProperties(D3D11_COMMON_TEXTURE_DESC* pDesc) { + if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0 || pDesc->ArraySize == 0) + return E_INVALIDARG; + + if (FAILED(DecodeSampleCount(pDesc->SampleDesc.Count, nullptr))) + return E_INVALIDARG; + + if ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_GDI_COMPATIBLE) + && (pDesc->Usage == D3D11_USAGE_STAGING + || (pDesc->Format != DXGI_FORMAT_B8G8R8A8_TYPELESS + && pDesc->Format != DXGI_FORMAT_B8G8R8A8_UNORM + && pDesc->Format != DXGI_FORMAT_B8G8R8A8_UNORM_SRGB))) + return E_INVALIDARG; + + if ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS) + && (pDesc->BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) + != (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) + return E_INVALIDARG; + + // TILE_POOL is invalid, but we don't support TILED either + if (pDesc->MiscFlags & (D3D11_RESOURCE_MISC_TILE_POOL | D3D11_RESOURCE_MISC_TILED)) + return E_INVALIDARG; + + // Use the maximum possible mip level count if the supplied + // mip level count is either unspecified (0) or invalid + const uint32_t maxMipLevelCount = pDesc->SampleDesc.Count <= 1 + ? util::computeMipLevelCount({ pDesc->Width, pDesc->Height, pDesc->Depth }) + : 1u; + + if (pDesc->MipLevels == 0 || pDesc->MipLevels > maxMipLevelCount) + pDesc->MipLevels = maxMipLevelCount; + + // Row-major is only supported for textures with one single + // subresource and one sample and cannot have bind flags. + if (pDesc->TextureLayout == D3D11_TEXTURE_LAYOUT_ROW_MAJOR + && (pDesc->MipLevels != 1 || pDesc->SampleDesc.Count != 1 || pDesc->BindFlags)) + return E_INVALIDARG; + + // Standard swizzle is unsupported + if (pDesc->TextureLayout == D3D11_TEXTURE_LAYOUT_64K_STANDARD_SWIZZLE) + return E_INVALIDARG; + + return S_OK; + } + + + BOOL D3D11CommonTexture::CheckImageSupport( + const DxvkImageCreateInfo* pImageInfo, + VkImageTiling Tiling) const { + const Rc<DxvkAdapter> adapter = m_device->GetDXVKDevice()->adapter(); + + VkImageUsageFlags usage = pImageInfo->usage; + + if (pImageInfo->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT) + usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + VkImageFormatProperties formatProps = { }; + VkResult status = adapter->imageFormatProperties( + pImageInfo->format, pImageInfo->type, Tiling, + usage, pImageInfo->flags, formatProps); + + if (status != VK_SUCCESS) + return FALSE; + + return (pImageInfo->extent.width <= formatProps.maxExtent.width) + && (pImageInfo->extent.height <= formatProps.maxExtent.height) + && (pImageInfo->extent.depth <= formatProps.maxExtent.depth) + && (pImageInfo->numLayers <= formatProps.maxArrayLayers) + && (pImageInfo->mipLevels <= formatProps.maxMipLevels) + && (pImageInfo->sampleCount & formatProps.sampleCounts); + } + + + BOOL D3D11CommonTexture::CheckFormatFeatureSupport( + VkFormat Format, + VkFormatFeatureFlags Features) const { + VkFormatProperties properties = m_device->GetDXVKDevice()->adapter()->formatProperties(Format); + + return (properties.linearTilingFeatures & Features) == Features + || (properties.optimalTilingFeatures & Features) == Features; + } + + + VkImageUsageFlags D3D11CommonTexture::EnableMetaCopyUsage( + VkFormat Format, + VkImageTiling Tiling) const { + VkFormatFeatureFlags requestedFeatures = 0; + + if (Format == VK_FORMAT_D16_UNORM || Format == VK_FORMAT_D32_SFLOAT) { + requestedFeatures |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT + | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + + if (Format == VK_FORMAT_R16_UNORM || Format == VK_FORMAT_R32_SFLOAT) { + requestedFeatures |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT + | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + } + + if (Format == VK_FORMAT_D32_SFLOAT_S8_UINT || Format == VK_FORMAT_D24_UNORM_S8_UINT) + requestedFeatures |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + + if (requestedFeatures == 0) + return 0; + + // Enable usage flags for all supported and requested features + VkFormatProperties properties = m_device->GetDXVKDevice()->adapter()->formatProperties(Format); + + requestedFeatures &= Tiling == VK_IMAGE_TILING_OPTIMAL + ? properties.optimalTilingFeatures + : properties.linearTilingFeatures; + + VkImageUsageFlags requestedUsage = 0; + + if (requestedFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) + requestedUsage |= VK_IMAGE_USAGE_SAMPLED_BIT; + + if (requestedFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) + requestedUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + if (requestedFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) + requestedUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + return requestedUsage; + } + + + VkImageUsageFlags D3D11CommonTexture::EnableMetaPackUsage( + VkFormat Format, + UINT CpuAccess) const { + if ((CpuAccess & D3D11_CPU_ACCESS_READ) == 0) + return 0; + + const auto dsMask = VK_IMAGE_ASPECT_DEPTH_BIT + | VK_IMAGE_ASPECT_STENCIL_BIT; + + auto formatInfo = imageFormatInfo(Format); + + return formatInfo->aspectMask == dsMask + ? VK_IMAGE_USAGE_SAMPLED_BIT + : 0; + } + + + D3D11_COMMON_TEXTURE_MAP_MODE D3D11CommonTexture::DetermineMapMode( + const DxvkImageCreateInfo* pImageInfo) const { + // Don't map an image unless the application requests it + if (!m_desc.CPUAccessFlags) + return D3D11_COMMON_TEXTURE_MAP_MODE_NONE; + + // If the resource cannot be used in the actual rendering pipeline, we + // do not need to create an actual image and can instead implement copy + // functions as buffer-to-image and image-to-buffer copies. + if (!m_desc.BindFlags && m_desc.Usage != D3D11_USAGE_DEFAULT) + return D3D11_COMMON_TEXTURE_MAP_MODE_STAGING; + + // Write-only images should go through a buffer for multiple reasons: + // 1. Some games do not respect the row and depth pitch that is returned + // by the Map() method, which leads to incorrect rendering (e.g. Nier) + // 2. Since the image will most likely be read for rendering by the GPU, + // writing the image to device-local image may be more efficient than + // reading its contents from host memory. + if (m_desc.Usage == D3D11_USAGE_DYNAMIC + && m_desc.TextureLayout != D3D11_TEXTURE_LAYOUT_ROW_MAJOR) + return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; + + // Depth-stencil formats in D3D11 can be mapped and follow special + // packing rules, so we need to copy that data into a buffer first + if (GetPackedDepthStencilFormat(m_desc.Format)) + return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; + + // Multi-plane images have a special memory layout in D3D11 + if (imageFormatInfo(pImageInfo->format)->flags.test(DxvkFormatFlag::MultiPlane)) + return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; + + // Images that can be read by the host should be mapped directly in + // order to avoid expensive synchronization with the GPU. This does + // however require linear tiling, which may not be supported for all + // combinations of image parameters. + return this->CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR) + ? D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT + : D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; + } + + + D3D11CommonTexture::MappedBuffer D3D11CommonTexture::CreateMappedBuffer(UINT MipLevel) const { + const DxvkFormatInfo* formatInfo = imageFormatInfo( + m_device->LookupPackedFormat(m_desc.Format, GetFormatMode()).Format); + + DxvkBufferCreateInfo info; + info.size = GetSubresourceLayout(formatInfo->aspectMask, MipLevel).Size; + info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT + | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT + | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + info.access = VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_TRANSFER_WRITE_BIT + | VK_ACCESS_SHADER_READ_BIT + | VK_ACCESS_SHADER_WRITE_BIT; + + VkMemoryPropertyFlags memType = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + if (m_desc.Usage == D3D11_USAGE_STAGING) + memType |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + + MappedBuffer result; + result.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType); + result.slice = result.buffer->getSliceHandle(); + return result; + } + + + VkImageType D3D11CommonTexture::GetImageTypeFromResourceDim(D3D11_RESOURCE_DIMENSION Dimension) { + switch (Dimension) { + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: return VK_IMAGE_TYPE_1D; + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: return VK_IMAGE_TYPE_2D; + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: return VK_IMAGE_TYPE_3D; + default: throw DxvkError("D3D11CommonTexture: Unhandled resource dimension"); + } + } + + + VkImageLayout D3D11CommonTexture::OptimizeLayout(VkImageUsageFlags Usage) { + const VkImageUsageFlags usageFlags = Usage; + + // Filter out unnecessary flags. Transfer operations + // are handled by the backend in a transparent manner. + Usage &= ~(VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + + // If the image is used only as an attachment, we never + // have to transform the image back to a different layout + if (Usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) + return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + if (Usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + Usage &= ~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + + // If the image is used for reading but not as a storage + // image, we can optimize the image for texture access + if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT) { + return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL + : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + // Otherwise, we have to stick with the default layout + return VK_IMAGE_LAYOUT_GENERAL; + } + + + + + D3D11DXGISurface::D3D11DXGISurface( + ID3D11Resource* pResource, + D3D11CommonTexture* pTexture) + : m_resource (pResource), + m_texture (pTexture), + m_gdiSurface(nullptr) { +#ifndef DXVK_NATIVE + if (pTexture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_GDI_COMPATIBLE) + m_gdiSurface = new D3D11GDISurface(m_resource, 0); +#endif + } + + + D3D11DXGISurface::~D3D11DXGISurface() { +#ifndef DXVK_NATIVE + if (m_gdiSurface) + delete m_gdiSurface; +#endif + } + + + ULONG STDMETHODCALLTYPE D3D11DXGISurface::AddRef() { + return m_resource->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11DXGISurface::Release() { + return m_resource->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_resource->QueryInterface(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetPrivateData( + REFGUID Name, + UINT* pDataSize, + void* pData) { + return m_resource->GetPrivateData(Name, pDataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::SetPrivateData( + REFGUID Name, + UINT DataSize, + const void* pData) { + return m_resource->SetPrivateData(Name, DataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::SetPrivateDataInterface( + REFGUID Name, + const IUnknown* pUnknown) { + return m_resource->SetPrivateDataInterface(Name, pUnknown); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetParent( + REFIID riid, + void** ppParent) { + return GetDevice(riid, ppParent); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetDevice( + REFIID riid, + void** ppDevice) { + Com<ID3D11Device> device; + m_resource->GetDevice(&device); + return device->QueryInterface(riid, ppDevice); + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetDesc( + DXGI_SURFACE_DESC* pDesc) { + if (!pDesc) + return DXGI_ERROR_INVALID_CALL; + + auto desc = m_texture->Desc(); + pDesc->Width = desc->Width; + pDesc->Height = desc->Height; + pDesc->Format = desc->Format; + pDesc->SampleDesc = desc->SampleDesc; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::Map( + DXGI_MAPPED_RECT* pLockedRect, + UINT MapFlags) { + Com<ID3D11Device> device; + Com<ID3D11DeviceContext> context; + + m_resource->GetDevice(&device); + device->GetImmediateContext(&context); + + if (pLockedRect) { + pLockedRect->Pitch = 0; + pLockedRect->pBits = nullptr; + } + + D3D11_MAP mapType; + + if (MapFlags & (DXGI_MAP_READ | DXGI_MAP_WRITE)) + mapType = D3D11_MAP_READ_WRITE; + else if (MapFlags & DXGI_MAP_READ) + mapType = D3D11_MAP_READ; + else if (MapFlags & (DXGI_MAP_WRITE | DXGI_MAP_DISCARD)) + mapType = D3D11_MAP_WRITE_DISCARD; + else if (MapFlags & DXGI_MAP_WRITE) + mapType = D3D11_MAP_WRITE; + else + return DXGI_ERROR_INVALID_CALL; + + D3D11_MAPPED_SUBRESOURCE sr; + HRESULT hr = context->Map(m_resource, 0, + mapType, 0, pLockedRect ? &sr : nullptr); + + if (hr != S_OK) + return hr; + + pLockedRect->Pitch = sr.RowPitch; + pLockedRect->pBits = reinterpret_cast<unsigned char*>(sr.pData); + return hr; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::Unmap() { + Com<ID3D11Device> device; + Com<ID3D11DeviceContext> context; + + m_resource->GetDevice(&device); + device->GetImmediateContext(&context); + + context->Unmap(m_resource, 0); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetDC( + BOOL Discard, + HDC* phdc) { +#ifndef DXVK_NATIVE + if (m_gdiSurface) + return m_gdiSurface->Acquire(Discard, phdc); +#endif + + return DXGI_ERROR_INVALID_CALL; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::ReleaseDC( + RECT* pDirtyRect) { +#ifndef DXVK_NATIVE + if (m_gdiSurface) + return m_gdiSurface->Release(pDirtyRect); +#endif + + return DXGI_ERROR_INVALID_CALL; + } + + + HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetResource( + REFIID riid, + void** ppParentResource, + UINT* pSubresourceIndex) { + HRESULT hr = m_resource->QueryInterface(riid, ppParentResource); + if (pSubresourceIndex) + *pSubresourceIndex = 0; + return hr; + } + + + bool D3D11DXGISurface::isSurfaceCompatible() const { + auto desc = m_texture->Desc(); + + return desc->ArraySize == 1 + && desc->MipLevels == 1; + } + + + + + D3D11VkInteropSurface::D3D11VkInteropSurface( + ID3D11Resource* pResource, + D3D11CommonTexture* pTexture) + : m_resource(pResource), + m_texture (pTexture) { + + } + + + D3D11VkInteropSurface::~D3D11VkInteropSurface() { + + } + + + ULONG STDMETHODCALLTYPE D3D11VkInteropSurface::AddRef() { + return m_resource->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11VkInteropSurface::Release() { + return m_resource->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11VkInteropSurface::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_resource->QueryInterface(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE D3D11VkInteropSurface::GetDevice( + IDXGIVkInteropDevice** ppDevice) { + Com<ID3D11Device> device; + m_resource->GetDevice(&device); + + return device->QueryInterface( + __uuidof(IDXGIVkInteropDevice), + reinterpret_cast<void**>(ppDevice)); + } + + + HRESULT STDMETHODCALLTYPE D3D11VkInteropSurface::GetVulkanImageInfo( + VkImage* pHandle, + VkImageLayout* pLayout, + VkImageCreateInfo* pInfo) { + const Rc<DxvkImage> image = m_texture->GetImage(); + const DxvkImageCreateInfo& info = image->info(); + + if (pHandle != nullptr) + *pHandle = image->handle(); + + if (pLayout != nullptr) + *pLayout = info.layout; + + if (pInfo != nullptr) { + // We currently don't support any extended structures + if (pInfo->sType != VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO + || pInfo->pNext != nullptr) + return E_INVALIDARG; + + pInfo->flags = 0; + pInfo->imageType = info.type; + pInfo->format = info.format; + pInfo->extent = info.extent; + pInfo->mipLevels = info.mipLevels; + pInfo->arrayLayers = info.numLayers; + pInfo->samples = info.sampleCount; + pInfo->tiling = info.tiling; + pInfo->usage = info.usage; + pInfo->sharingMode = VK_SHARING_MODE_EXCLUSIVE; + pInfo->queueFamilyIndexCount = 0; + pInfo->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + } + + return S_OK; + } + + + /////////////////////////////////////////// + // D 3 D 1 1 T E X T U R E 1 D + D3D11Texture1D::D3D11Texture1D( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc) + : D3D11DeviceChild<ID3D11Texture1D>(pDevice), + m_texture (pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, VK_NULL_HANDLE), + m_interop (this, &m_texture), + m_surface (this, &m_texture), + m_resource(this), + m_d3d10 (this) { + + } + + + D3D11Texture1D::~D3D11Texture1D() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11Texture1D::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11Resource) + || riid == __uuidof(ID3D11Texture1D)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10Resource) + || riid == __uuidof(ID3D10Texture1D)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + if (m_surface.isSurfaceCompatible() + && (riid == __uuidof(IDXGISurface) + || riid == __uuidof(IDXGISurface1) + || riid == __uuidof(IDXGISurface2))) { + *ppvObject = ref(&m_surface); + return S_OK; + } + + if (riid == __uuidof(IDXGIObject) + || riid == __uuidof(IDXGIDeviceSubObject) + || riid == __uuidof(IDXGIResource) + || riid == __uuidof(IDXGIResource1)) { + *ppvObject = ref(&m_resource); + return S_OK; + } + + if (riid == __uuidof(IDXGIVkInteropSurface)) { + *ppvObject = ref(&m_interop); + return S_OK; + } + + Logger::warn("D3D11Texture1D::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11Texture1D::GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) { + *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE1D; + } + + + UINT STDMETHODCALLTYPE D3D11Texture1D::GetEvictionPriority() { + return DXGI_RESOURCE_PRIORITY_NORMAL; + } + + + void STDMETHODCALLTYPE D3D11Texture1D::SetEvictionPriority(UINT EvictionPriority) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11Texture1D::SetEvictionPriority: Stub"); + } + + + void STDMETHODCALLTYPE D3D11Texture1D::GetDesc(D3D11_TEXTURE1D_DESC *pDesc) { + pDesc->Width = m_texture.Desc()->Width; + pDesc->MipLevels = m_texture.Desc()->MipLevels; + pDesc->ArraySize = m_texture.Desc()->ArraySize; + pDesc->Format = m_texture.Desc()->Format; + pDesc->Usage = m_texture.Desc()->Usage; + pDesc->BindFlags = m_texture.Desc()->BindFlags; + pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags; + pDesc->MiscFlags = m_texture.Desc()->MiscFlags; + } + + + /////////////////////////////////////////// + // D 3 D 1 1 T E X T U R E 2 D + D3D11Texture2D::D3D11Texture2D( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc) + : D3D11DeviceChild<ID3D11Texture2D1>(pDevice), + m_texture (pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, VK_NULL_HANDLE), + m_interop (this, &m_texture), + m_surface (this, &m_texture), + m_resource(this), + m_d3d10 (this) { + + } + + + D3D11Texture2D::D3D11Texture2D( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc, + DXGI_USAGE DxgiUsage, + VkImage vkImage) + : D3D11DeviceChild<ID3D11Texture2D1>(pDevice), + m_texture (pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, vkImage), + m_interop (this, &m_texture), + m_surface (this, &m_texture), + m_resource(this), + m_d3d10 (this) { + + } + + + D3D11Texture2D::~D3D11Texture2D() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11Texture2D::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11Resource) + || riid == __uuidof(ID3D11Texture2D) + || riid == __uuidof(ID3D11Texture2D1)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10Resource) + || riid == __uuidof(ID3D10Texture2D)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + if (m_surface.isSurfaceCompatible() + && (riid == __uuidof(IDXGISurface) + || riid == __uuidof(IDXGISurface1) + || riid == __uuidof(IDXGISurface2))) { + *ppvObject = ref(&m_surface); + return S_OK; + } + + if (riid == __uuidof(IDXGIObject) + || riid == __uuidof(IDXGIDeviceSubObject) + || riid == __uuidof(IDXGIResource) + || riid == __uuidof(IDXGIResource1)) { + *ppvObject = ref(&m_resource); + return S_OK; + } + + if (riid == __uuidof(IDXGIVkInteropSurface)) { + *ppvObject = ref(&m_interop); + return S_OK; + } + + Logger::warn("D3D11Texture2D::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11Texture2D::GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) { + *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D; + } + + + UINT STDMETHODCALLTYPE D3D11Texture2D::GetEvictionPriority() { + return DXGI_RESOURCE_PRIORITY_NORMAL; + } + + + void STDMETHODCALLTYPE D3D11Texture2D::SetEvictionPriority(UINT EvictionPriority) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11Texture2D::SetEvictionPriority: Stub"); + } + + + void STDMETHODCALLTYPE D3D11Texture2D::GetDesc(D3D11_TEXTURE2D_DESC* pDesc) { + pDesc->Width = m_texture.Desc()->Width; + pDesc->Height = m_texture.Desc()->Height; + pDesc->MipLevels = m_texture.Desc()->MipLevels; + pDesc->ArraySize = m_texture.Desc()->ArraySize; + pDesc->Format = m_texture.Desc()->Format; + pDesc->SampleDesc = m_texture.Desc()->SampleDesc; + pDesc->Usage = m_texture.Desc()->Usage; + pDesc->BindFlags = m_texture.Desc()->BindFlags; + pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags; + pDesc->MiscFlags = m_texture.Desc()->MiscFlags; + } + + + void STDMETHODCALLTYPE D3D11Texture2D::GetDesc1(D3D11_TEXTURE2D_DESC1* pDesc) { + pDesc->Width = m_texture.Desc()->Width; + pDesc->Height = m_texture.Desc()->Height; + pDesc->MipLevels = m_texture.Desc()->MipLevels; + pDesc->ArraySize = m_texture.Desc()->ArraySize; + pDesc->Format = m_texture.Desc()->Format; + pDesc->SampleDesc = m_texture.Desc()->SampleDesc; + pDesc->Usage = m_texture.Desc()->Usage; + pDesc->BindFlags = m_texture.Desc()->BindFlags; + pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags; + pDesc->MiscFlags = m_texture.Desc()->MiscFlags; + pDesc->TextureLayout = m_texture.Desc()->TextureLayout; + } + + + /////////////////////////////////////////// + // D 3 D 1 1 T E X T U R E 3 D + D3D11Texture3D::D3D11Texture3D( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc) + : D3D11DeviceChild<ID3D11Texture3D1>(pDevice), + m_texture (pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, VK_NULL_HANDLE), + m_interop (this, &m_texture), + m_resource(this), + m_d3d10 (this) { + + } + + + D3D11Texture3D::~D3D11Texture3D() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11Texture3D::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11Resource) + || riid == __uuidof(ID3D11Texture3D) + || riid == __uuidof(ID3D11Texture3D1)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10Resource) + || riid == __uuidof(ID3D10Texture3D)) { + *ppvObject = ref(&m_d3d10); + return S_OK; + } + + if (riid == __uuidof(IDXGIObject) + || riid == __uuidof(IDXGIDeviceSubObject) + || riid == __uuidof(IDXGIResource) + || riid == __uuidof(IDXGIResource1)) { + *ppvObject = ref(&m_resource); + return S_OK; + } + + if (riid == __uuidof(IDXGIVkInteropSurface)) { + *ppvObject = ref(&m_interop); + return S_OK; + } + + Logger::warn("D3D11Texture3D::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11Texture3D::GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) { + *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE3D; + } + + + UINT STDMETHODCALLTYPE D3D11Texture3D::GetEvictionPriority() { + return DXGI_RESOURCE_PRIORITY_NORMAL; + } + + + void STDMETHODCALLTYPE D3D11Texture3D::SetEvictionPriority(UINT EvictionPriority) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("D3D11Texture3D::SetEvictionPriority: Stub"); + } + + + void STDMETHODCALLTYPE D3D11Texture3D::GetDesc(D3D11_TEXTURE3D_DESC* pDesc) { + pDesc->Width = m_texture.Desc()->Width; + pDesc->Height = m_texture.Desc()->Height; + pDesc->Depth = m_texture.Desc()->Depth; + pDesc->MipLevels = m_texture.Desc()->MipLevels; + pDesc->Format = m_texture.Desc()->Format; + pDesc->Usage = m_texture.Desc()->Usage; + pDesc->BindFlags = m_texture.Desc()->BindFlags; + pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags; + pDesc->MiscFlags = m_texture.Desc()->MiscFlags; + } + + + void STDMETHODCALLTYPE D3D11Texture3D::GetDesc1(D3D11_TEXTURE3D_DESC1* pDesc) { + pDesc->Width = m_texture.Desc()->Width; + pDesc->Height = m_texture.Desc()->Height; + pDesc->Depth = m_texture.Desc()->Depth; + pDesc->MipLevels = m_texture.Desc()->MipLevels; + pDesc->Format = m_texture.Desc()->Format; + pDesc->Usage = m_texture.Desc()->Usage; + pDesc->BindFlags = m_texture.Desc()->BindFlags; + pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags; + pDesc->MiscFlags = m_texture.Desc()->MiscFlags; + } + + + D3D11CommonTexture* GetCommonTexture(ID3D11Resource* pResource) { + D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&dimension); + + switch (dimension) { + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: + return static_cast<D3D11Texture1D*>(pResource)->GetCommonTexture(); + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + return static_cast<D3D11Texture2D*>(pResource)->GetCommonTexture(); + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + return static_cast<D3D11Texture3D*>(pResource)->GetCommonTexture(); + + default: + return nullptr; + } + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.h new file mode 100644 index 00000000..80901a85 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.h @@ -0,0 +1,628 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_texture.h" + +#include "d3d11_device_child.h" +#include "d3d11_interfaces.h" +#include "d3d11_resource.h" + +namespace dxvk { + + class D3D11Device; + class D3D11GDISurface; + + /** + * \brief Image memory mapping mode + * + * Determines how exactly \c Map will + * behave when mapping an image. + */ + enum D3D11_COMMON_TEXTURE_MAP_MODE { + D3D11_COMMON_TEXTURE_MAP_MODE_NONE, ///< Not mapped + D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, ///< Mapped through buffer + D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, ///< Directly mapped to host mem + D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, ///< Buffer only, no image + }; + + + /** + * \brief Common texture description + * + * Contains all members that can be + * defined for 1D, 2D and 3D textures. + */ + struct D3D11_COMMON_TEXTURE_DESC { + UINT Width; + UINT Height; + UINT Depth; + UINT MipLevels; + UINT ArraySize; + DXGI_FORMAT Format; + DXGI_SAMPLE_DESC SampleDesc; + D3D11_USAGE Usage; + UINT BindFlags; + UINT CPUAccessFlags; + UINT MiscFlags; + D3D11_TEXTURE_LAYOUT TextureLayout; + }; + + + /** + * \brief Packed subresource layout + */ + struct D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT { + UINT64 Offset; + UINT64 Size; + UINT RowPitch; + UINT DepthPitch; + }; + + + /** + * \brief D3D11 common texture object + * + * This class implements common texture methods and + * aims to work around the issue that there are three + * different interfaces for basically the same thing. + */ + class D3D11CommonTexture { + + public: + + D3D11CommonTexture( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc, + D3D11_RESOURCE_DIMENSION Dimension, + DXGI_USAGE DxgiUsage, + VkImage vkImage); + + ~D3D11CommonTexture(); + + /** + * \brief Texture properties + * + * The returned data can be used to fill in + * \c D3D11_TEXTURE2D_DESC and similar structs. + * \returns Pointer to texture description + */ + const D3D11_COMMON_TEXTURE_DESC* Desc() const { + return &m_desc; + } + + /** + * \brief Retrieves Vulkan image type + * + * Returns the image type based on the D3D11 resource + * dimension. Also works if there is no actual image. + * \returns Vulkan image type + */ + VkImageType GetVkImageType() const { + return GetImageTypeFromResourceDim(m_dimension); + } + + /** + * \brief Computes extent of a given mip level + * + * This also works for staging resources that have no image. + * \param [in] Level Mip level to compute the size of + */ + VkExtent3D MipLevelExtent(uint32_t Level) const { + return util::computeMipLevelExtent( + VkExtent3D { m_desc.Width, m_desc.Height, m_desc.Depth }, Level); + } + + /** + * \brief Special DXGI usage flags + * + * Flags that are set in addition to the bind + * flags. Zero for application-created textures. + * \returns DXGI usage flags + */ + DXGI_USAGE GetDxgiUsage() const { + return m_dxgiUsage; + } + + /** + * \brief Counts number of subresources + * \returns Number of subresources + */ + UINT CountSubresources() const { + return m_desc.ArraySize * m_desc.MipLevels; + } + + /** + * \brief Map mode + * \returns Map mode + */ + D3D11_COMMON_TEXTURE_MAP_MODE GetMapMode() const { + return m_mapMode; + } + + /** + * \brief Map type of a given subresource + * + * \param [in] Subresource Subresource index + * \returns Current map mode of that subresource + */ + D3D11_MAP GetMapType(UINT Subresource) const { + return Subresource < m_mapTypes.size() + ? D3D11_MAP(m_mapTypes[Subresource]) + : D3D11_MAP(~0u); + } + + /** + * \brief Sets map type for a given subresource + * + * \param [in] Subresource The subresource + * \param [in] MapType The map type + */ + void SetMapType(UINT Subresource, D3D11_MAP MapType) { + if (Subresource < m_mapTypes.size()) + m_mapTypes[Subresource] = MapType; + } + + /** + * \brief The DXVK image + * \returns The DXVK image + */ + Rc<DxvkImage> GetImage() const { + return m_image; + } + + /** + * \brief Mapped subresource buffer + * + * \param [in] Subresource Subresource index + * \returns Mapped subresource buffer + */ + Rc<DxvkBuffer> GetMappedBuffer(UINT Subresource) const { + return Subresource < m_buffers.size() + ? m_buffers[Subresource].buffer + : Rc<DxvkBuffer>(); + } + + /** + * \brief Discards mapped buffer slice for a given subresource + * + * \param [in] Subresource Subresource to discard + * \returns Newly allocated mapped buffer slice + */ + DxvkBufferSliceHandle DiscardSlice(UINT Subresource) { + if (Subresource < m_buffers.size()) { + DxvkBufferSliceHandle slice = m_buffers[Subresource].buffer->allocSlice(); + m_buffers[Subresource].slice = slice; + return slice; + } else { + return DxvkBufferSliceHandle(); + } + } + + /** + * \brief Retrieves mapped buffer slice for a given subresource + * + * \param [in] Subresource Subresource index to query + * \returns Currently mapped buffer slice + */ + DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) const { + return Subresource < m_buffers.size() + ? m_buffers[Subresource].slice + : DxvkBufferSliceHandle(); + } + + /** + * \brief Returns underlying packed Vulkan format + * + * This works even for staging resources that have no image. + * Note that for depth-stencil resources, the returned format + * may be different from the image format on some systems. + * \returns Packed Vulkan format + */ + VkFormat GetPackedFormat() const { + return m_packedFormat; + } + + /** + * \brief Computes pixel offset into mapped buffer + * + * \param [in] Subresource Subresource index + * \param [in] Subresource Plane index + * \param [in] Offset Pixel coordinate to compute offset for + * \returns Offset into mapped subresource buffer, in pixels + */ + VkDeviceSize ComputeMappedOffset(UINT Subresource, UINT Plane, VkOffset3D Offset) const; + + /** + * \brief Computes subresource from the subresource index + * + * Used by some functions that operate on only + * one subresource, such as \c UpdateSubresource. + * \param [in] Aspect The image aspect + * \param [in] Subresource Subresource index + * \returns The Vulkan image subresource + */ + VkImageSubresource GetSubresourceFromIndex( + VkImageAspectFlags Aspect, + UINT Subresource) const; + + /** + * \brief Computes subresource layout for the given subresource + * + * \param [in] AspectMask The image aspect + * \param [in] Subresource Subresource index + * \returns Memory layout of the mapped subresource + */ + D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT GetSubresourceLayout( + VkImageAspectFlags AspectMask, + UINT Subresource) const; + + /** + * \brief Format mode + * + * Determines whether the image is going to + * be used as a color image or a depth image. + * \returns Format mode + */ + DXGI_VK_FORMAT_MODE GetFormatMode() const; + + /** + * \brief Computes plane count + * + * For non-planar formats, the plane count will be 1. + * \returns Image plane count + */ + uint32_t GetPlaneCount() const; + + /** + * \brief Checks whether a view can be created for this textue + * + * View formats are only compatible if they are either identical + * or from the same family of typeless formats, where the resource + * format must be typeless and the view format must be typed. This + * will also check whether the required bind flags are supported. + * \param [in] BindFlags Bind flags for the view + * \param [in] Format The desired view format + * \param [in] Plane Plane slice for planar formats + * \returns \c true if the format is compatible + */ + bool CheckViewCompatibility( + UINT BindFlags, + DXGI_FORMAT Format, + UINT Plane) const; + + /** + * \brief Normalizes and validates texture description + * + * Fills in undefined values and validates the texture + * parameters. Any error returned by this method should + * be forwarded to the application. + * \param [in,out] pDesc Texture description + * \returns \c S_OK if the parameters are valid + */ + static HRESULT NormalizeTextureProperties( + D3D11_COMMON_TEXTURE_DESC* pDesc); + + private: + + struct MappedBuffer { + Rc<DxvkBuffer> buffer; + DxvkBufferSliceHandle slice; + }; + + D3D11Device* const m_device; + D3D11_RESOURCE_DIMENSION m_dimension; + D3D11_COMMON_TEXTURE_DESC m_desc; + D3D11_COMMON_TEXTURE_MAP_MODE m_mapMode; + DXGI_USAGE m_dxgiUsage; + VkFormat m_packedFormat; + + Rc<DxvkImage> m_image; + std::vector<MappedBuffer> m_buffers; + std::vector<D3D11_MAP> m_mapTypes; + + MappedBuffer CreateMappedBuffer( + UINT MipLevel) const; + + BOOL CheckImageSupport( + const DxvkImageCreateInfo* pImageInfo, + VkImageTiling Tiling) const; + + BOOL CheckFormatFeatureSupport( + VkFormat Format, + VkFormatFeatureFlags Features) const; + + VkImageUsageFlags EnableMetaCopyUsage( + VkFormat Format, + VkImageTiling Tiling) const; + + VkImageUsageFlags EnableMetaPackUsage( + VkFormat Format, + UINT CpuAccess) const; + + D3D11_COMMON_TEXTURE_MAP_MODE DetermineMapMode( + const DxvkImageCreateInfo* pImageInfo) const; + + static VkImageType GetImageTypeFromResourceDim( + D3D11_RESOURCE_DIMENSION Dimension); + + static VkImageLayout OptimizeLayout( + VkImageUsageFlags Usage); + + }; + + + /** + * \brief IDXGISurface implementation for D3D11 textures + * + * Provides an implementation for 2D textures that + * have only one array layer and one mip level. + */ + class D3D11DXGISurface : public IDXGISurface2 { + + public: + + D3D11DXGISurface( + ID3D11Resource* pResource, + D3D11CommonTexture* pTexture); + + ~D3D11DXGISurface(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE GetPrivateData( + REFGUID Name, + UINT* pDataSize, + void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateData( + REFGUID Name, + UINT DataSize, + const void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + REFGUID Name, + const IUnknown* pUnknown); + + HRESULT STDMETHODCALLTYPE GetParent( + REFIID riid, + void** ppParent); + + HRESULT STDMETHODCALLTYPE GetDevice( + REFIID riid, + void** ppDevice); + + HRESULT STDMETHODCALLTYPE GetDesc( + DXGI_SURFACE_DESC* pDesc); + + HRESULT STDMETHODCALLTYPE Map( + DXGI_MAPPED_RECT* pLockedRect, + UINT MapFlags); + + HRESULT STDMETHODCALLTYPE Unmap(); + + HRESULT STDMETHODCALLTYPE GetDC( + BOOL Discard, + HDC* phdc); + + HRESULT STDMETHODCALLTYPE ReleaseDC( + RECT* pDirtyRect); + + HRESULT STDMETHODCALLTYPE GetResource( + REFIID riid, + void** ppParentResource, + UINT* pSubresourceIndex); + + bool isSurfaceCompatible() const; + + private: + + ID3D11Resource* m_resource; + D3D11CommonTexture* m_texture; + D3D11GDISurface* m_gdiSurface; + + }; + + + /** + * \brief Common texture interop class + * + * Provides access to the underlying Vulkan + * texture to external Vulkan libraries. + */ + class D3D11VkInteropSurface : public IDXGIVkInteropSurface { + + public: + + D3D11VkInteropSurface( + ID3D11Resource* pResource, + D3D11CommonTexture* pTexture); + + ~D3D11VkInteropSurface(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE GetDevice( + IDXGIVkInteropDevice** ppDevice); + + HRESULT STDMETHODCALLTYPE GetVulkanImageInfo( + VkImage* pHandle, + VkImageLayout* pLayout, + VkImageCreateInfo* pInfo); + + private: + + ID3D11Resource* m_resource; + D3D11CommonTexture* m_texture; + + }; + + + /////////////////////////////////////////// + // D 3 D 1 1 T E X T U R E 1 D + class D3D11Texture1D : public D3D11DeviceChild<ID3D11Texture1D> { + + public: + + D3D11Texture1D( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc); + + ~D3D11Texture1D(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void STDMETHODCALLTYPE GetType( + D3D11_RESOURCE_DIMENSION *pResourceDimension) final; + + UINT STDMETHODCALLTYPE GetEvictionPriority() final; + + void STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) final; + + void STDMETHODCALLTYPE GetDesc( + D3D11_TEXTURE1D_DESC *pDesc) final; + + D3D11CommonTexture* GetCommonTexture() { + return &m_texture; + } + + D3D10Texture1D* GetD3D10Iface() { + return &m_d3d10; + } + + private: + + D3D11CommonTexture m_texture; + D3D11VkInteropSurface m_interop; + D3D11DXGISurface m_surface; + D3D11DXGIResource m_resource; + D3D10Texture1D m_d3d10; + + }; + + + /////////////////////////////////////////// + // D 3 D 1 1 T E X T U R E 2 D + class D3D11Texture2D : public D3D11DeviceChild<ID3D11Texture2D1> { + + public: + + D3D11Texture2D( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc); + + D3D11Texture2D( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc, + DXGI_USAGE DxgiUsage, + VkImage vkImage); + + ~D3D11Texture2D(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void STDMETHODCALLTYPE GetType( + D3D11_RESOURCE_DIMENSION *pResourceDimension) final; + + UINT STDMETHODCALLTYPE GetEvictionPriority() final; + + void STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) final; + + void STDMETHODCALLTYPE GetDesc( + D3D11_TEXTURE2D_DESC* pDesc) final; + + void STDMETHODCALLTYPE GetDesc1( + D3D11_TEXTURE2D_DESC1* pDesc) final; + + D3D11CommonTexture* GetCommonTexture() { + return &m_texture; + } + + D3D10Texture2D* GetD3D10Iface() { + return &m_d3d10; + } + + private: + + D3D11CommonTexture m_texture; + D3D11VkInteropSurface m_interop; + D3D11DXGISurface m_surface; + D3D11DXGIResource m_resource; + D3D10Texture2D m_d3d10; + + }; + + + /////////////////////////////////////////// + // D 3 D 1 1 T E X T U R E 3 D + class D3D11Texture3D : public D3D11DeviceChild<ID3D11Texture3D1> { + + public: + + D3D11Texture3D( + D3D11Device* pDevice, + const D3D11_COMMON_TEXTURE_DESC* pDesc); + + ~D3D11Texture3D(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject) final; + + void STDMETHODCALLTYPE GetType( + D3D11_RESOURCE_DIMENSION *pResourceDimension) final; + + UINT STDMETHODCALLTYPE GetEvictionPriority() final; + + void STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) final; + + void STDMETHODCALLTYPE GetDesc( + D3D11_TEXTURE3D_DESC* pDesc) final; + + void STDMETHODCALLTYPE GetDesc1( + D3D11_TEXTURE3D_DESC1* pDesc) final; + + D3D11CommonTexture* GetCommonTexture() { + return &m_texture; + } + + D3D10Texture3D* GetD3D10Iface() { + return &m_d3d10; + } + + private: + + D3D11CommonTexture m_texture; + D3D11VkInteropSurface m_interop; + D3D11DXGIResource m_resource; + D3D10Texture3D m_d3d10; + + }; + + + /** + * \brief Retrieves texture from resource pointer + * + * \param [in] pResource The resource to query + * \returns Pointer to texture info, or \c nullptr + */ + D3D11CommonTexture* GetCommonTexture( + ID3D11Resource* pResource); + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.cpp new file mode 100644 index 00000000..d4448c54 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.cpp @@ -0,0 +1,141 @@ +#include "d3d11_util.h" + +namespace dxvk { + + HRESULT DecodeSampleCount(UINT Count, VkSampleCountFlagBits* pCount) { + VkSampleCountFlagBits flag; + + switch (Count) { + case 1: flag = VK_SAMPLE_COUNT_1_BIT; break; + case 2: flag = VK_SAMPLE_COUNT_2_BIT; break; + case 4: flag = VK_SAMPLE_COUNT_4_BIT; break; + case 8: flag = VK_SAMPLE_COUNT_8_BIT; break; + case 16: flag = VK_SAMPLE_COUNT_16_BIT; break; + default: return E_INVALIDARG; + } + + if (pCount != nullptr) { + *pCount = flag; + return S_OK; + } return S_FALSE; + } + + + VkSamplerAddressMode DecodeAddressMode( + D3D11_TEXTURE_ADDRESS_MODE mode) { + switch (mode) { + case D3D11_TEXTURE_ADDRESS_WRAP: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + + case D3D11_TEXTURE_ADDRESS_MIRROR: + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + + case D3D11_TEXTURE_ADDRESS_CLAMP: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + case D3D11_TEXTURE_ADDRESS_BORDER: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + + case D3D11_TEXTURE_ADDRESS_MIRROR_ONCE: + return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; + + default: + Logger::err(str::format("D3D11: Unsupported address mode: ", mode)); + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + } + } + + + VkCompareOp DecodeCompareOp(D3D11_COMPARISON_FUNC Mode) { + switch (Mode) { + case D3D11_COMPARISON_NEVER: return VK_COMPARE_OP_NEVER; + case D3D11_COMPARISON_LESS: return VK_COMPARE_OP_LESS; + case D3D11_COMPARISON_EQUAL: return VK_COMPARE_OP_EQUAL; + case D3D11_COMPARISON_LESS_EQUAL: return VK_COMPARE_OP_LESS_OR_EQUAL; + case D3D11_COMPARISON_GREATER: return VK_COMPARE_OP_GREATER; + case D3D11_COMPARISON_NOT_EQUAL: return VK_COMPARE_OP_NOT_EQUAL; + case D3D11_COMPARISON_GREATER_EQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL; + case D3D11_COMPARISON_ALWAYS: return VK_COMPARE_OP_ALWAYS; + } + + if (Mode != 0) // prevent log spamming when apps use ZeroMemory + Logger::err(str::format("D3D11: Unsupported compare op: ", Mode)); + return VK_COMPARE_OP_NEVER; + } + + + VkConservativeRasterizationModeEXT DecodeConservativeRasterizationMode( + D3D11_CONSERVATIVE_RASTERIZATION_MODE Mode) { + switch (Mode) { + case D3D11_CONSERVATIVE_RASTERIZATION_MODE_OFF: + return VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT; + case D3D11_CONSERVATIVE_RASTERIZATION_MODE_ON: + return VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT; + } + + Logger::err(str::format("D3D11: Unsupported conservative raster mode: ", Mode)); + return VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT; + } + + + VkShaderStageFlagBits GetShaderStage(DxbcProgramType ProgramType) { + switch (ProgramType) { + case DxbcProgramType::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT; + case DxbcProgramType::HullShader: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + case DxbcProgramType::DomainShader: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + case DxbcProgramType::GeometryShader: return VK_SHADER_STAGE_GEOMETRY_BIT; + case DxbcProgramType::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT; + case DxbcProgramType::ComputeShader: return VK_SHADER_STAGE_COMPUTE_BIT; + default: return VkShaderStageFlagBits(0); + } + } + + + VkFormatFeatureFlags GetBufferFormatFeatures(UINT BindFlags) { + VkFormatFeatureFlags features = 0; + + if (BindFlags & D3D11_BIND_SHADER_RESOURCE) + features |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT; + if (BindFlags & D3D11_BIND_UNORDERED_ACCESS) + features |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT; + + return features; + } + + + VkFormatFeatureFlags GetImageFormatFeatures(UINT BindFlags) { + VkFormatFeatureFlags features = 0; + + if (BindFlags & D3D11_BIND_DEPTH_STENCIL) + features |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + if (BindFlags & D3D11_BIND_RENDER_TARGET) + features |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + if (BindFlags & D3D11_BIND_SHADER_RESOURCE) + features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + if (BindFlags & D3D11_BIND_UNORDERED_ACCESS) + features |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; + + return features; + } + + + VkFormat GetPackedDepthStencilFormat(DXGI_FORMAT Format) { + switch (Format) { + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + return VK_FORMAT_D24_UNORM_S8_UINT; + + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + return VK_FORMAT_D32_SFLOAT_S8_UINT; + + default: + return VK_FORMAT_UNDEFINED; + } + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.h new file mode 100644 index 00000000..749dc8be --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.h @@ -0,0 +1,46 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../dxbc/dxbc_util.h" + +#include "d3d11_include.h" + +namespace dxvk { + + template<typename T> + UINT CompactSparseList(T* pData, UINT Mask) { + uint32_t count = 0; + + for (uint32_t id : bit::BitMask(Mask)) + pData[count++] = pData[id]; + + return count; + } + + HRESULT DecodeSampleCount( + UINT Count, + VkSampleCountFlagBits* pCount); + + VkSamplerAddressMode DecodeAddressMode( + D3D11_TEXTURE_ADDRESS_MODE mode); + + VkCompareOp DecodeCompareOp( + D3D11_COMPARISON_FUNC Mode); + + VkConservativeRasterizationModeEXT DecodeConservativeRasterizationMode( + D3D11_CONSERVATIVE_RASTERIZATION_MODE Mode); + + VkShaderStageFlagBits GetShaderStage( + DxbcProgramType ProgramType); + + VkFormatFeatureFlags GetBufferFormatFeatures( + UINT BindFlags); + + VkFormatFeatureFlags GetImageFormatFeatures( + UINT BindFlags); + + VkFormat GetPackedDepthStencilFormat( + DXGI_FORMAT Format); + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.cpp new file mode 100644 index 00000000..db534659 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.cpp @@ -0,0 +1,1303 @@ +#include <algorithm> + +#include "d3d11_context.h" +#include "d3d11_context_imm.h" +#include "d3d11_video.h" + +#include <d3d11_video_blit_frag.h> +#include <d3d11_video_blit_vert.h> + +namespace dxvk { + + D3D11VideoProcessorEnumerator::D3D11VideoProcessorEnumerator( + D3D11Device* pDevice, + const D3D11_VIDEO_PROCESSOR_CONTENT_DESC& Desc) + : D3D11DeviceChild<ID3D11VideoProcessorEnumerator>(pDevice), + m_desc(Desc) { + + } + + + D3D11VideoProcessorEnumerator::~D3D11VideoProcessorEnumerator() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::QueryInterface( + REFIID riid, + void** ppvObject) { + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11VideoProcessorEnumerator)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11VideoProcessorEnumerator::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorContentDesc( + D3D11_VIDEO_PROCESSOR_CONTENT_DESC* pContentDesc) { + *pContentDesc = m_desc; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::CheckVideoProcessorFormat( + DXGI_FORMAT Format, + UINT* pFlags) { + Logger::err("D3D11VideoProcessorEnumerator::CheckVideoProcessorFormat: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorCaps( + D3D11_VIDEO_PROCESSOR_CAPS* pCaps) { + Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorCaps: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorRateConversionCaps( + UINT TypeIndex, + D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS* pCaps) { + Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorRateConversionCaps: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorCustomRate( + UINT TypeIndex, + UINT CustomRateIndex, + D3D11_VIDEO_PROCESSOR_CUSTOM_RATE* pRate) { + Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorCustomRate: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorFilterRange( + D3D11_VIDEO_PROCESSOR_FILTER Filter, + D3D11_VIDEO_PROCESSOR_FILTER_RANGE* pRange) { + Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorFilterRange: Stub"); + return E_NOTIMPL; + } + + + + + D3D11VideoProcessor::D3D11VideoProcessor( + D3D11Device* pDevice, + D3D11VideoProcessorEnumerator* pEnumerator, + UINT RateConversionIndex) + : D3D11DeviceChild<ID3D11VideoProcessor>(pDevice), + m_enumerator(pEnumerator), m_rateConversionIndex(RateConversionIndex) { + + } + + + D3D11VideoProcessor::~D3D11VideoProcessor() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessor::QueryInterface( + REFIID riid, + void** ppvObject) { + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11VideoProcessor)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11VideoProcessor::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11VideoProcessor::GetContentDesc( + D3D11_VIDEO_PROCESSOR_CONTENT_DESC *pDesc) { + m_enumerator->GetVideoProcessorContentDesc(pDesc); + } + + + void STDMETHODCALLTYPE D3D11VideoProcessor::GetRateConversionCaps( + D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS *pCaps) { + m_enumerator->GetVideoProcessorRateConversionCaps(m_rateConversionIndex, pCaps); + } + + + + + D3D11VideoProcessorInputView::D3D11VideoProcessorInputView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC& Desc) + : D3D11DeviceChild<ID3D11VideoProcessorInputView>(pDevice), + m_resource(pResource), m_desc(Desc) { + D3D11_COMMON_RESOURCE_DESC resourceDesc = { }; + GetCommonResourceDesc(pResource, &resourceDesc); + + Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage(); + + if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) { + DxvkImageCreateInfo info = dxvkImage->info(); + info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; + info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + info.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + info.shared = VK_FALSE; + dxvkImage = m_copy = pDevice->GetDXVKDevice()->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + + DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR); + DXGI_VK_FORMAT_FAMILY formatFamily = pDevice->LookupFamily(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR); + + VkImageAspectFlags aspectMask = imageFormatInfo(formatInfo.Format)->aspectMask; + + DxvkImageViewCreateInfo viewInfo; + viewInfo.format = formatInfo.Format; + viewInfo.swizzle = formatInfo.Swizzle; + viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + + switch (m_desc.ViewDimension) { + case D3D11_VPIV_DIMENSION_TEXTURE2D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = m_desc.Texture2D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_RTV_DIMENSION_UNKNOWN: + throw DxvkError("Invalid view dimension"); + } + + m_subresources.aspectMask = aspectMask; + m_subresources.baseArrayLayer = viewInfo.minLayer; + m_subresources.layerCount = viewInfo.numLayers; + m_subresources.mipLevel = viewInfo.minLevel; + + for (uint32_t i = 0; aspectMask && i < m_views.size(); i++) { + viewInfo.aspect = vk::getNextAspect(aspectMask); + + if (viewInfo.aspect != VK_IMAGE_ASPECT_COLOR_BIT) + viewInfo.format = formatFamily.Formats[i]; + + m_views[i] = pDevice->GetDXVKDevice()->createImageView(dxvkImage, viewInfo); + } + + m_isYCbCr = IsYCbCrFormat(resourceDesc.Format); + } + + + D3D11VideoProcessorInputView::~D3D11VideoProcessorInputView() { + + } + + + bool D3D11VideoProcessorInputView::IsYCbCrFormat(DXGI_FORMAT Format) { + static const std::array<DXGI_FORMAT, 3> s_formats = {{ + DXGI_FORMAT_NV12, + DXGI_FORMAT_YUY2, + DXGI_FORMAT_AYUV, + }}; + + return std::find(s_formats.begin(), s_formats.end(), Format) != s_formats.end(); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorInputView::QueryInterface( + REFIID riid, + void** ppvObject) { + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11View) + || riid == __uuidof(ID3D11VideoProcessorInputView)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11VideoProcessorInputView::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11VideoProcessorInputView::GetResource( + ID3D11Resource** ppResource) { + *ppResource = m_resource.ref(); + } + + + void STDMETHODCALLTYPE D3D11VideoProcessorInputView::GetDesc( + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC* pDesc) { + *pDesc = m_desc; + } + + + + D3D11VideoProcessorOutputView::D3D11VideoProcessorOutputView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC& Desc) + : D3D11DeviceChild<ID3D11VideoProcessorOutputView>(pDevice), + m_resource(pResource), m_desc(Desc) { + D3D11_COMMON_RESOURCE_DESC resourceDesc = { }; + GetCommonResourceDesc(pResource, &resourceDesc); + + DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat( + resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR); + + DxvkImageViewCreateInfo viewInfo; + viewInfo.format = formatInfo.Format; + viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask; + viewInfo.swizzle = formatInfo.Swizzle; + viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + switch (m_desc.ViewDimension) { + case D3D11_VPOV_DIMENSION_TEXTURE2D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = m_desc.Texture2D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_VPOV_DIMENSION_TEXTURE2DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = m_desc.Texture2DArray.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = m_desc.Texture2DArray.FirstArraySlice; + viewInfo.numLayers = m_desc.Texture2DArray.ArraySize; + break; + + case D3D11_RTV_DIMENSION_UNKNOWN: + throw DxvkError("Invalid view dimension"); + } + + m_view = pDevice->GetDXVKDevice()->createImageView( + GetCommonTexture(pResource)->GetImage(), viewInfo); + } + + + D3D11VideoProcessorOutputView::~D3D11VideoProcessorOutputView() { + + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoProcessorOutputView::QueryInterface( + REFIID riid, + void** ppvObject) { + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11View) + || riid == __uuidof(ID3D11VideoProcessorOutputView)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11VideoProcessorOutputView::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11VideoProcessorOutputView::GetResource( + ID3D11Resource** ppResource) { + *ppResource = m_resource.ref(); + } + + + void STDMETHODCALLTYPE D3D11VideoProcessorOutputView::GetDesc( + D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc) { + *pDesc = m_desc; + } + + + + D3D11VideoContext::D3D11VideoContext( + D3D11ImmediateContext* pContext, + const Rc<DxvkDevice>& Device) + : m_ctx(pContext) { + const SpirvCodeBuffer vsCode(d3d11_video_blit_vert); + const SpirvCodeBuffer fsCode(d3d11_video_blit_frag); + + const std::array<DxvkResourceSlot, 4> fsResourceSlots = {{ + { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC }, + { 1, VK_DESCRIPTOR_TYPE_SAMPLER }, + { 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D }, + { 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D }, + }}; + + m_vs = Device->createShader( + VK_SHADER_STAGE_VERTEX_BIT, + 0, nullptr, { 0u, 1u }, + vsCode); + + m_fs = Device->createShader( + VK_SHADER_STAGE_FRAGMENT_BIT, + fsResourceSlots.size(), + fsResourceSlots.data(), + { 1u, 1u, 0u, 0u }, + fsCode); + + DxvkSamplerCreateInfo samplerInfo; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerInfo.mipmapLodBias = 0.0f; + samplerInfo.mipmapLodMin = 0.0f; + samplerInfo.mipmapLodMax = 0.0f; + samplerInfo.useAnisotropy = VK_FALSE; + samplerInfo.maxAnisotropy = 1.0f; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.compareToDepth = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.borderColor = VkClearColorValue(); + samplerInfo.usePixelCoord = VK_FALSE; + m_sampler = Device->createSampler(samplerInfo); + + DxvkBufferCreateInfo bufferInfo; + bufferInfo.size = sizeof(UboData); + bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bufferInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + bufferInfo.access = VK_ACCESS_UNIFORM_READ_BIT; + m_ubo = Device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + + + D3D11VideoContext::~D3D11VideoContext() { + + } + + + ULONG STDMETHODCALLTYPE D3D11VideoContext::AddRef() { + return m_ctx->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11VideoContext::Release() { + return m_ctx->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_ctx->QueryInterface(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::GetPrivateData( + REFGUID Name, + UINT* pDataSize, + void* pData) { + return m_ctx->GetPrivateData(Name, pDataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::SetPrivateData( + REFGUID Name, + UINT DataSize, + const void* pData) { + return m_ctx->SetPrivateData(Name, DataSize, pData); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::SetPrivateDataInterface( + REFGUID Name, + const IUnknown* pUnknown) { + return m_ctx->SetPrivateDataInterface(Name, pUnknown); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::GetDevice( + ID3D11Device** ppDevice) { + return m_ctx->GetDevice(ppDevice); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::GetDecoderBuffer( + ID3D11VideoDecoder* pDecoder, + D3D11_VIDEO_DECODER_BUFFER_TYPE Type, + UINT* BufferSize, + void** ppBuffer) { + Logger::err("D3D11VideoContext::GetDecoderBuffer: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::ReleaseDecoderBuffer( + ID3D11VideoDecoder* pDecoder, + D3D11_VIDEO_DECODER_BUFFER_TYPE Type) { + Logger::err("D3D11VideoContext::ReleaseDecoderBuffer: Stub"); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::DecoderBeginFrame( + ID3D11VideoDecoder* pDecoder, + ID3D11VideoDecoderOutputView* pView, + UINT KeySize, + const void* pKey) { + Logger::err("D3D11VideoContext::DecoderBeginFrame: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::DecoderEndFrame( + ID3D11VideoDecoder* pDecoder) { + Logger::err("D3D11VideoContext::DecoderEndFrame: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::SubmitDecoderBuffers( + ID3D11VideoDecoder* pDecoder, + UINT BufferCount, + const D3D11_VIDEO_DECODER_BUFFER_DESC* pBufferDescs) { + Logger::err("D3D11VideoContext::SubmitDecoderBuffers: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::DecoderExtension( + ID3D11VideoDecoder* pDecoder, + const D3D11_VIDEO_DECODER_EXTENSION* pExtension) { + Logger::err("D3D11VideoContext::DecoderExtension: Stub"); + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputTargetRect( + ID3D11VideoProcessor* pVideoProcessor, + BOOL Enable, + const RECT* pRect) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState(); + state->outputTargetRectEnabled = Enable; + + if (Enable) + state->outputTargetRect = *pRect; + + static bool errorShown = false; + + if (!std::exchange(errorShown, true)) + Logger::err("D3D11VideoContext::VideoProcessorSetOutputTargetRect: Stub."); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputBackgroundColor( + ID3D11VideoProcessor* pVideoProcessor, + BOOL YCbCr, + const D3D11_VIDEO_COLOR* pColor) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState(); + state->outputBackgroundColorIsYCbCr = YCbCr; + state->outputBackgroundColor = *pColor; + + static bool errorShown = false; + + if (!std::exchange(errorShown, true)) + Logger::err("D3D11VideoContext::VideoProcessorSetOutputBackgroundColor: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputColorSpace( + ID3D11VideoProcessor* pVideoProcessor, + const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState(); + state->outputColorSpace = *pColorSpace; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputAlphaFillMode( + ID3D11VideoProcessor* pVideoProcessor, + D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE AlphaFillMode, + UINT StreamIndex) { + Logger::err("D3D11VideoContext::VideoProcessorSetOutputAlphaFillMode: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputConstriction( + ID3D11VideoProcessor* pVideoProcessor, + BOOL Enable, + SIZE Size) { + Logger::err("D3D11VideoContext::VideoProcessorSetOutputConstriction: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputStereoMode( + ID3D11VideoProcessor* pVideoProcessor, + BOOL Enable) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState(); + state->outputStereoModeEnabled = Enable; + + if (Enable) + Logger::err("D3D11VideoContext: Stereo output not supported"); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputExtension( + ID3D11VideoProcessor* pVideoProcessor, + const GUID* pExtensionGuid, + UINT DataSize, + void* pData) { + Logger::err("D3D11VideoContext::VideoProcessorSetOutputExtension: Stub"); + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamFrameFormat( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_FRAME_FORMAT Format) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->frameFormat = Format; + + if (Format != D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE) + Logger::err(str::format("D3D11VideoContext: Unsupported frame format: ", Format)); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamColorSpace( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->colorSpace = *pColorSpace; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamOutputRate( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_OUTPUT_RATE Rate, + BOOL Repeat, + const DXGI_RATIONAL* CustomRate) { + Logger::err("D3D11VideoContext::VideoProcessorSetStreamOutputRate: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamSourceRect( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + const RECT* pRect) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->srcRectEnabled = Enable; + + if (Enable) + state->srcRect = *pRect; + + static bool errorShown = false; + + if (!std::exchange(errorShown, true)) + Logger::err("D3D11VideoContext::VideoProcessorSetStreamSourceRect: Stub."); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamDestRect( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + const RECT* pRect) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->dstRectEnabled = Enable; + + if (Enable) + state->dstRect = *pRect; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamAlpha( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + FLOAT Alpha) { + Logger::err("D3D11VideoContext::VideoProcessorSetStreamAlpha: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamPalette( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + UINT EntryCount, + const UINT* pEntries) { + Logger::err("D3D11VideoContext::VideoProcessorSetStreamPalette: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamPixelAspectRatio( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + const DXGI_RATIONAL* pSrcAspectRatio, + const DXGI_RATIONAL* pDstAspectRatio) { + Logger::err("D3D11VideoContext::VideoProcessorSetStreamPixelAspectRatio: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamLumaKey( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + FLOAT Lower, + FLOAT Upper) { + Logger::err("D3D11VideoContext::VideoProcessorSetStreamLumaKey: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamStereoFormat( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT Format, + BOOL LeftViewFrame0, + BOOL BaseViewFrame0, + D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE FlipMode, + int MonoOffset) { + Logger::err("D3D11VideoContext::VideoProcessorSetStreamStereoFormat: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamAutoProcessingMode( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->autoProcessingEnabled = Enable; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamFilter( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_FILTER Filter, + BOOL Enable, + int Level) { + Logger::err("D3D11VideoContext::VideoProcessorSetStreamFilter: Stub"); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamExtension( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + const GUID* pExtensionGuid, + UINT DataSize, + void* pData) { + Logger::err("D3D11VideoContext::VideoProcessorSetStreamExtension: Stub"); + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamRotation( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + D3D11_VIDEO_PROCESSOR_ROTATION Rotation) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->rotationEnabled = Enable; + state->rotation = Rotation; + + if (Enable && Rotation != D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY) + Logger::err(str::format("D3D11VideoContext: Unsupported rotation: ", Rotation)); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputTargetRect( + ID3D11VideoProcessor* pVideoProcessor, + BOOL* pEnabled, + RECT* pRect) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState(); + + if (pEnabled) + *pEnabled = state->outputTargetRectEnabled; + + if (pRect) + *pRect = state->outputTargetRect; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputBackgroundColor( + ID3D11VideoProcessor* pVideoProcessor, + BOOL* pYCbCr, + D3D11_VIDEO_COLOR* pColor) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState(); + + if (pYCbCr) + *pYCbCr = state->outputBackgroundColorIsYCbCr; + + if (pColor) + *pColor = state->outputBackgroundColor; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputColorSpace( + ID3D11VideoProcessor* pVideoProcessor, + D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState(); + + if (pColorSpace) + *pColorSpace = state->outputColorSpace; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputAlphaFillMode( + ID3D11VideoProcessor* pVideoProcessor, + D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE* pAlphaFillMode, + UINT* pStreamIndex) { + Logger::err("D3D11VideoContext::VideoProcessorGetOutputAlphaFillMode: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputConstriction( + ID3D11VideoProcessor* pVideoProcessor, + BOOL* pEnabled, + SIZE* pSize) { + Logger::err("D3D11VideoContext::VideoProcessorGetOutputConstriction: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputStereoMode( + ID3D11VideoProcessor* pVideoProcessor, + BOOL* pEnabled) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState(); + + if (pEnabled) + *pEnabled = state->outputStereoModeEnabled; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputExtension( + ID3D11VideoProcessor* pVideoProcessor, + const GUID* pExtensionGuid, + UINT DataSize, + void* pData) { + Logger::err("D3D11VideoContext::VideoProcessorGetOutputExtension: Stub"); + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamFrameFormat( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_FRAME_FORMAT* pFormat) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pFormat) + *pFormat = state->frameFormat; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamColorSpace( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pColorSpace) + *pColorSpace = state->colorSpace; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamOutputRate( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_OUTPUT_RATE* pRate, + BOOL* pRepeat, + DXGI_RATIONAL* pCustomRate) { + Logger::err("D3D11VideoContext::VideoProcessorGetStreamOutputRate: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamSourceRect( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + RECT* pRect) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pEnabled) + *pEnabled = state->srcRectEnabled; + + if (pRect) + *pRect = state->srcRect; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamDestRect( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + RECT* pRect) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pEnabled) + *pEnabled = state->dstRectEnabled; + + if (pRect) + *pRect = state->dstRect; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamAlpha( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + FLOAT* pAlpha) { + Logger::err("D3D11VideoContext::VideoProcessorGetStreamAlpha: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamPalette( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + UINT EntryCount, + UINT* pEntries) { + Logger::err("D3D11VideoContext::VideoProcessorGetStreamPalette: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamPixelAspectRatio( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + DXGI_RATIONAL* pSrcAspectRatio, + DXGI_RATIONAL* pDstAspectRatio) { + Logger::err("D3D11VideoContext::VideoProcessorGetStreamPixelAspectRatio: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamLumaKey( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + FLOAT* pLower, + FLOAT* pUpper) { + Logger::err("D3D11VideoContext::VideoProcessorGetStreamLumaKey: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamStereoFormat( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT* pFormat, + BOOL* pLeftViewFrame0, + BOOL* pBaseViewFrame0, + D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE* pFlipMode, + int* pMonoOffset) { + Logger::err("D3D11VideoContext::VideoProcessorGetStreamStereoFormat: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamAutoProcessingMode( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + *pEnabled = state->autoProcessingEnabled; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamFilter( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_FILTER Filter, + BOOL* pEnabled, + int* pLevel) { + Logger::err("D3D11VideoContext::VideoProcessorGetStreamFilter: Stub"); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamExtension( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + const GUID* pExtensionGuid, + UINT DataSize, + void* pData) { + Logger::err("D3D11VideoContext::VideoProcessorGetStreamExtension: Stub"); + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamRotation( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnable, + D3D11_VIDEO_PROCESSOR_ROTATION* pRotation) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pEnable) + *pEnable = state->rotationEnabled; + + if (pRotation) + *pRotation = state->rotation; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorBlt( + ID3D11VideoProcessor* pVideoProcessor, + ID3D11VideoProcessorOutputView* pOutputView, + UINT FrameIdx, + UINT StreamCount, + const D3D11_VIDEO_PROCESSOR_STREAM* pStreams) { + D3D10DeviceLock lock = m_ctx->LockContext(); + + auto videoProcessor = static_cast<D3D11VideoProcessor*>(pVideoProcessor); + bool hasStreamsEnabled = false; + + // Resetting and restoring all context state incurs + // a lot of overhead, so only do it as necessary + for (uint32_t i = 0; i < StreamCount; i++) { + auto streamState = videoProcessor->GetStreamState(i); + + if (!pStreams[i].Enable || !streamState) + continue; + + if (!hasStreamsEnabled) { + m_ctx->ResetState(); + BindOutputView(pOutputView); + hasStreamsEnabled = true; + } + + BlitStream(streamState, &pStreams[i]); + } + + if (hasStreamsEnabled) + m_ctx->RestoreState(); + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::NegotiateCryptoSessionKeyExchange( + ID3D11CryptoSession* pSession, + UINT DataSize, + void* pData) { + Logger::err("D3D11VideoContext::NegotiateCryptoSessionKeyExchange: Stub"); + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11VideoContext::EncryptionBlt( + ID3D11CryptoSession* pSession, + ID3D11Texture2D* pSrcSurface, + ID3D11Texture2D* pDstSurface, + UINT IVSize, + void* pIV) { + Logger::err("D3D11VideoContext::EncryptionBlt: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::DecryptionBlt( + ID3D11CryptoSession* pSession, + ID3D11Texture2D* pSrcSurface, + ID3D11Texture2D* pDstSurface, + D3D11_ENCRYPTED_BLOCK_INFO* pBlockInfo, + UINT KeySize, + const void* pKey, + UINT IVSize, + void* pIV) { + Logger::err("D3D11VideoContext::DecryptionBlt: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::StartSessionKeyRefresh( + ID3D11CryptoSession* pSession, + UINT RandomNumberSize, + void* pRandomNumber) { + Logger::err("D3D11VideoContext::StartSessionKeyRefresh: Stub"); + } + + + void STDMETHODCALLTYPE D3D11VideoContext::FinishSessionKeyRefresh( + ID3D11CryptoSession* pSession) { + Logger::err("D3D11VideoContext::FinishSessionKeyRefresh: Stub"); + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::GetEncryptionBltKey( + ID3D11CryptoSession* pSession, + UINT KeySize, + void* pKey) { + Logger::err("D3D11VideoContext::GetEncryptionBltKey: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::NegotiateAuthenticatedChannelKeyExchange( + ID3D11AuthenticatedChannel* pChannel, + UINT DataSize, + void* pData) { + Logger::err("D3D11VideoContext::NegotiateAuthenticatedChannelKeyExchange: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::QueryAuthenticatedChannel( + ID3D11AuthenticatedChannel* pChannel, + UINT InputSize, + const void* pInput, + UINT OutputSize, + void* pOutput) { + Logger::err("D3D11VideoContext::QueryAuthenticatedChannel: Stub"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE D3D11VideoContext::ConfigureAuthenticatedChannel( + ID3D11AuthenticatedChannel* pChannel, + UINT InputSize, + const void* pInput, + D3D11_AUTHENTICATED_CONFIGURE_OUTPUT* pOutput) { + Logger::err("D3D11VideoContext::ConfigureAuthenticatedChannel: Stub"); + return E_NOTIMPL; + } + + + void D3D11VideoContext::ApplyColorMatrix(float pDst[3][4], const float pSrc[3][4]) { + float result[3][4]; + + for (uint32_t i = 0; i < 3; i++) { + for (uint32_t j = 0; j < 4; j++) { + result[i][j] = pSrc[i][0] * pDst[0][j] + + pSrc[i][1] * pDst[1][j] + + pSrc[i][2] * pDst[2][j] + + pSrc[i][3] * float(j == 3); + } + } + + memcpy(pDst, &result[0][0], sizeof(result)); + } + + + void D3D11VideoContext::ApplyYCbCrMatrix(float pColorMatrix[3][4], bool UseBt709) { + static const float pretransform[3][4] = { + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, -0.5f }, + { 1.0f, 0.0f, 0.0f, -0.5f }, + }; + + static const float bt601[3][4] = { + { 1.0f, 0.000000f, 1.402000f, 0.0f }, + { 1.0f, -0.344136f, -0.714136f, 0.0f }, + { 1.0f, 1.772000f, 0.000000f, 0.0f }, + }; + + static const float bt709[3][4] = { + { 1.0f, 0.000000f, 1.574800f, 0.0f }, + { 1.0f, -0.187324f, -0.468124f, 0.0f }, + { 1.0f, 1.855600f, 0.000000f, 0.0f }, + }; + + ApplyColorMatrix(pColorMatrix, pretransform); + ApplyColorMatrix(pColorMatrix, UseBt709 ? bt709 : bt601); + } + + + void D3D11VideoContext::BindOutputView( + ID3D11VideoProcessorOutputView* pOutputView) { + auto dxvkView = static_cast<D3D11VideoProcessorOutputView*>(pOutputView)->GetView(); + + m_ctx->EmitCs([this, cView = dxvkView] (DxvkContext* ctx) { + DxvkRenderTargets rt; + rt.color[0].view = cView; + rt.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + ctx->bindRenderTargets(rt); + ctx->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_vs); + ctx->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_fs); + ctx->bindResourceBuffer(0, DxvkBufferSlice(m_ubo)); + + DxvkInputAssemblyState iaState; + iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + iaState.primitiveRestart = VK_FALSE; + iaState.patchVertexCount = 0; + ctx->setInputAssemblyState(iaState); + }); + + VkExtent3D viewExtent = dxvkView->mipLevelExtent(0); + m_dstExtent = { viewExtent.width, viewExtent.height }; + } + + + void D3D11VideoContext::BlitStream( + const D3D11VideoProcessorStreamState* pStreamState, + const D3D11_VIDEO_PROCESSOR_STREAM* pStream) { + if (pStream->PastFrames || pStream->FutureFrames) + Logger::err("D3D11VideoContext: Ignoring non-zero PastFrames and FutureFrames"); + + if (pStream->OutputIndex) + Logger::err("D3D11VideoContext: Ignoring non-zero OutputIndex"); + + if (pStream->InputFrameOrField) + Logger::err("D3D11VideoContext: Ignoring non-zero InputFrameOrField"); + + auto view = static_cast<D3D11VideoProcessorInputView*>(pStream->pInputSurface); + + if (view->NeedsCopy()) { + m_ctx->EmitCs([ + cDstImage = view->GetShadowCopy(), + cSrcImage = view->GetImage(), + cSrcLayers = view->GetImageSubresources() + ] (DxvkContext* ctx) { + VkImageSubresourceLayers cDstLayers; + cDstLayers.aspectMask = cSrcLayers.aspectMask; + cDstLayers.baseArrayLayer = 0; + cDstLayers.layerCount = cSrcLayers.layerCount; + cDstLayers.mipLevel = cSrcLayers.mipLevel; + + ctx->copyImage( + cDstImage, cDstLayers, VkOffset3D(), + cSrcImage, cSrcLayers, VkOffset3D(), + cDstImage->info().extent); + }); + } + + m_ctx->EmitCs([this, + cStreamState = *pStreamState, + cViews = view->GetViews(), + cIsYCbCr = view->IsYCbCr() + ] (DxvkContext* ctx) { + VkViewport viewport; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = float(m_dstExtent.width); + viewport.height = float(m_dstExtent.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor; + scissor.offset = { 0, 0 }; + scissor.extent = m_dstExtent; + + if (cStreamState.dstRectEnabled) { + viewport.x = float(cStreamState.dstRect.left); + viewport.y = float(cStreamState.dstRect.top); + viewport.width = float(cStreamState.dstRect.right) - viewport.x; + viewport.height = float(cStreamState.dstRect.bottom) - viewport.y; + } + + UboData uboData = { }; + uboData.colorMatrix[0][0] = 1.0f; + uboData.colorMatrix[1][1] = 1.0f; + uboData.colorMatrix[2][2] = 1.0f; + uboData.coordMatrix[0][0] = 1.0f; + uboData.coordMatrix[1][1] = 1.0f; + uboData.yMin = 0.0f; + uboData.yMax = 1.0f; + + if (cIsYCbCr) + ApplyYCbCrMatrix(uboData.colorMatrix, cStreamState.colorSpace.YCbCr_Matrix); + + if (cStreamState.colorSpace.Nominal_Range) { + uboData.yMin = 0.0627451f; + uboData.yMax = 0.9215686f; + } + + DxvkBufferSliceHandle uboSlice = m_ubo->allocSlice(); + memcpy(uboSlice.mapPtr, &uboData, sizeof(uboData)); + + ctx->invalidateBuffer(m_ubo, uboSlice); + ctx->setViewports(1, &viewport, &scissor); + ctx->bindResourceSampler(1, m_sampler); + + for (uint32_t i = 0; i < cViews.size(); i++) + ctx->bindResourceView(2 + i, cViews[i], nullptr); + + ctx->draw(3, 1, 0, 0); + }); + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.h new file mode 100644 index 00000000..85979eb8 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.h @@ -0,0 +1,612 @@ +#pragma once + +#include "d3d11_device.h" + +namespace dxvk { + + static constexpr uint32_t D3D11_VK_VIDEO_STREAM_COUNT = 8; + + class D3D11VideoProcessorEnumerator : public D3D11DeviceChild<ID3D11VideoProcessorEnumerator> { + + public: + + D3D11VideoProcessorEnumerator( + D3D11Device* pDevice, + const D3D11_VIDEO_PROCESSOR_CONTENT_DESC& Desc); + + ~D3D11VideoProcessorEnumerator(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE GetVideoProcessorContentDesc( + D3D11_VIDEO_PROCESSOR_CONTENT_DESC* pContentDesc); + + HRESULT STDMETHODCALLTYPE CheckVideoProcessorFormat( + DXGI_FORMAT Format, + UINT* pFlags); + + HRESULT STDMETHODCALLTYPE GetVideoProcessorCaps( + D3D11_VIDEO_PROCESSOR_CAPS* pCaps); + + HRESULT STDMETHODCALLTYPE GetVideoProcessorRateConversionCaps( + UINT TypeIndex, + D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS* pCaps); + + HRESULT STDMETHODCALLTYPE GetVideoProcessorCustomRate( + UINT TypeIndex, + UINT CustomRateIndex, + D3D11_VIDEO_PROCESSOR_CUSTOM_RATE* pRate); + + HRESULT STDMETHODCALLTYPE GetVideoProcessorFilterRange( + D3D11_VIDEO_PROCESSOR_FILTER Filter, + D3D11_VIDEO_PROCESSOR_FILTER_RANGE* pRange); + + private: + + D3D11_VIDEO_PROCESSOR_CONTENT_DESC m_desc; + + }; + + + struct D3D11VideoProcessorStreamState { + BOOL autoProcessingEnabled = TRUE; + BOOL dstRectEnabled = FALSE; + BOOL srcRectEnabled = FALSE; + BOOL rotationEnabled = FALSE; + RECT dstRect = RECT(); + RECT srcRect = RECT(); + D3D11_VIDEO_FRAME_FORMAT frameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; + D3D11_VIDEO_PROCESSOR_ROTATION rotation = D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY; + D3D11_VIDEO_PROCESSOR_COLOR_SPACE colorSpace = D3D11_VIDEO_PROCESSOR_COLOR_SPACE(); + }; + + struct D3D11VideoProcessorState { + BOOL outputStereoModeEnabled = FALSE; + BOOL outputBackgroundColorIsYCbCr = FALSE; + BOOL outputTargetRectEnabled = FALSE; + RECT outputTargetRect = RECT(); + D3D11_VIDEO_COLOR outputBackgroundColor = D3D11_VIDEO_COLOR(); + D3D11_VIDEO_PROCESSOR_COLOR_SPACE outputColorSpace = D3D11_VIDEO_PROCESSOR_COLOR_SPACE(); + }; + + class D3D11VideoProcessor : public D3D11DeviceChild<ID3D11VideoProcessor> { + + public: + + D3D11VideoProcessor( + D3D11Device* pDevice, + D3D11VideoProcessorEnumerator* pEnumerator, + UINT RateConversionIndex); + + ~D3D11VideoProcessor(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void STDMETHODCALLTYPE GetContentDesc( + D3D11_VIDEO_PROCESSOR_CONTENT_DESC *pDesc); + + void STDMETHODCALLTYPE GetRateConversionCaps( + D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS *pCaps); + + D3D11VideoProcessorState* GetState() { + return &m_state; + } + + D3D11VideoProcessorStreamState* GetStreamState(UINT StreamIndex) { + return StreamIndex < D3D11_VK_VIDEO_STREAM_COUNT + ? &m_streams[StreamIndex] + : nullptr; + } + + private: + + D3D11VideoProcessorEnumerator* m_enumerator; + uint32_t m_rateConversionIndex; + D3D11VideoProcessorState m_state; + D3D11VideoProcessorStreamState m_streams[D3D11_VK_VIDEO_STREAM_COUNT]; + + }; + + + + class D3D11VideoProcessorInputView : public D3D11DeviceChild<ID3D11VideoProcessorInputView> { + + public: + + D3D11VideoProcessorInputView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC& Desc); + + ~D3D11VideoProcessorInputView(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void STDMETHODCALLTYPE GetResource( + ID3D11Resource** ppResource); + + void STDMETHODCALLTYPE GetDesc( + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC* pDesc); + + const bool IsYCbCr() const { + return m_isYCbCr; + } + + const bool NeedsCopy() const { + return m_copy != nullptr; + } + + Rc<DxvkImage> GetImage() const { + return GetCommonTexture(m_resource.ptr())->GetImage(); + } + + VkImageSubresourceLayers GetImageSubresources() const { + return m_subresources; + } + + Rc<DxvkImage> GetShadowCopy() const { + return m_copy; + } + + std::array<Rc<DxvkImageView>, 2> GetViews() const { + return m_views; + } + + private: + + Com<ID3D11Resource> m_resource; + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC m_desc; + VkImageSubresourceLayers m_subresources; + Rc<DxvkImage> m_copy; + std::array<Rc<DxvkImageView>, 2> m_views; + bool m_isYCbCr = false; + + static bool IsYCbCrFormat(DXGI_FORMAT Format); + + }; + + + + class D3D11VideoProcessorOutputView : public D3D11DeviceChild<ID3D11VideoProcessorOutputView> { + + public: + + D3D11VideoProcessorOutputView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC& Desc); + + ~D3D11VideoProcessorOutputView(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void STDMETHODCALLTYPE GetResource( + ID3D11Resource** ppResource); + + void STDMETHODCALLTYPE GetDesc( + D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc); + + Rc<DxvkImageView> GetView() const { + return m_view; + } + + private: + + Com<ID3D11Resource> m_resource; + D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC m_desc; + Rc<DxvkImageView> m_view; + + }; + + + + class D3D11VideoContext : public ID3D11VideoContext { + + public: + + D3D11VideoContext( + D3D11ImmediateContext* pContext, + const Rc<DxvkDevice>& Device); + + ~D3D11VideoContext(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE GetPrivateData( + REFGUID Name, + UINT* pDataSize, + void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateData( + REFGUID Name, + UINT DataSize, + const void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( + REFGUID Name, + const IUnknown* pUnknown); + + void STDMETHODCALLTYPE GetDevice( + ID3D11Device** ppDevice); + + HRESULT STDMETHODCALLTYPE GetDecoderBuffer( + ID3D11VideoDecoder* pDecoder, + D3D11_VIDEO_DECODER_BUFFER_TYPE Type, + UINT* BufferSize, + void** ppBuffer); + + HRESULT STDMETHODCALLTYPE ReleaseDecoderBuffer( + ID3D11VideoDecoder* pDecoder, + D3D11_VIDEO_DECODER_BUFFER_TYPE Type); + + HRESULT STDMETHODCALLTYPE DecoderBeginFrame( + ID3D11VideoDecoder* pDecoder, + ID3D11VideoDecoderOutputView* pView, + UINT KeySize, + const void* pKey); + + HRESULT STDMETHODCALLTYPE DecoderEndFrame( + ID3D11VideoDecoder* pDecoder); + + HRESULT STDMETHODCALLTYPE SubmitDecoderBuffers( + ID3D11VideoDecoder* pDecoder, + UINT BufferCount, + const D3D11_VIDEO_DECODER_BUFFER_DESC* pBufferDescs); + + HRESULT STDMETHODCALLTYPE DecoderExtension( + ID3D11VideoDecoder* pDecoder, + const D3D11_VIDEO_DECODER_EXTENSION* pExtension); + + void STDMETHODCALLTYPE VideoProcessorSetOutputTargetRect( + ID3D11VideoProcessor* pVideoProcessor, + BOOL Enable, + const RECT* pRect); + + void STDMETHODCALLTYPE VideoProcessorSetOutputBackgroundColor( + ID3D11VideoProcessor* pVideoProcessor, + BOOL YCbCr, + const D3D11_VIDEO_COLOR* pColor); + + void STDMETHODCALLTYPE VideoProcessorSetOutputColorSpace( + ID3D11VideoProcessor* pVideoProcessor, + const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace); + + void STDMETHODCALLTYPE VideoProcessorSetOutputAlphaFillMode( + ID3D11VideoProcessor* pVideoProcessor, + D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE AlphaFillMode, + UINT StreamIndex); + + void STDMETHODCALLTYPE VideoProcessorSetOutputConstriction( + ID3D11VideoProcessor* pVideoProcessor, + BOOL Enable, + SIZE Size); + + void STDMETHODCALLTYPE VideoProcessorSetOutputStereoMode( + ID3D11VideoProcessor* pVideoProcessor, + BOOL Enable); + + HRESULT STDMETHODCALLTYPE VideoProcessorSetOutputExtension( + ID3D11VideoProcessor* pVideoProcessor, + const GUID* pExtensionGuid, + UINT DataSize, + void* pData); + + void STDMETHODCALLTYPE VideoProcessorSetStreamFrameFormat( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_FRAME_FORMAT Format); + + void STDMETHODCALLTYPE VideoProcessorSetStreamColorSpace( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace); + + void STDMETHODCALLTYPE VideoProcessorSetStreamOutputRate( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_OUTPUT_RATE Rate, + BOOL Repeat, + const DXGI_RATIONAL* CustomRate); + + void STDMETHODCALLTYPE VideoProcessorSetStreamSourceRect( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + const RECT* pRect); + + void STDMETHODCALLTYPE VideoProcessorSetStreamDestRect( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + const RECT* pRect); + + void STDMETHODCALLTYPE VideoProcessorSetStreamAlpha( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + FLOAT Alpha); + + void STDMETHODCALLTYPE VideoProcessorSetStreamPalette( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + UINT EntryCount, + const UINT* pEntries); + + void STDMETHODCALLTYPE VideoProcessorSetStreamPixelAspectRatio( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + const DXGI_RATIONAL* pSrcAspectRatio, + const DXGI_RATIONAL* pDstAspectRatio); + + void STDMETHODCALLTYPE VideoProcessorSetStreamLumaKey( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + FLOAT Lower, + FLOAT Upper); + + void STDMETHODCALLTYPE VideoProcessorSetStreamStereoFormat( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT Format, + BOOL LeftViewFrame0, + BOOL BaseViewFrame0, + D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE FlipMode, + int MonoOffset); + + void STDMETHODCALLTYPE VideoProcessorSetStreamAutoProcessingMode( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable); + + void STDMETHODCALLTYPE VideoProcessorSetStreamFilter( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_FILTER Filter, + BOOL Enable, + int Level); + + HRESULT STDMETHODCALLTYPE VideoProcessorSetStreamExtension( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + const GUID* pExtensionGuid, + UINT DataSize, + void* pData); + + void STDMETHODCALLTYPE VideoProcessorSetStreamRotation( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL Enable, + D3D11_VIDEO_PROCESSOR_ROTATION Rotation); + + void STDMETHODCALLTYPE VideoProcessorGetOutputTargetRect( + ID3D11VideoProcessor* pVideoProcessor, + BOOL* pEnabled, + RECT* pRect); + + void STDMETHODCALLTYPE VideoProcessorGetOutputBackgroundColor( + ID3D11VideoProcessor* pVideoProcessor, + BOOL* pYCbCr, + D3D11_VIDEO_COLOR* pColor); + + void STDMETHODCALLTYPE VideoProcessorGetOutputColorSpace( + ID3D11VideoProcessor* pVideoProcessor, + D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace); + + void STDMETHODCALLTYPE VideoProcessorGetOutputAlphaFillMode( + ID3D11VideoProcessor* pVideoProcessor, + D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE* pAlphaFillMode, + UINT* pStreamIndex); + + void STDMETHODCALLTYPE VideoProcessorGetOutputConstriction( + ID3D11VideoProcessor* pVideoProcessor, + BOOL* pEnabled, + SIZE* pSize); + + void STDMETHODCALLTYPE VideoProcessorGetOutputStereoMode( + ID3D11VideoProcessor* pVideoProcessor, + BOOL* pEnabled); + + HRESULT STDMETHODCALLTYPE VideoProcessorGetOutputExtension( + ID3D11VideoProcessor* pVideoProcessor, + const GUID* pExtensionGuid, + UINT DataSize, + void* pData); + + void STDMETHODCALLTYPE VideoProcessorGetStreamFrameFormat( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_FRAME_FORMAT* pFormat); + + void STDMETHODCALLTYPE VideoProcessorGetStreamColorSpace( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace); + + void STDMETHODCALLTYPE VideoProcessorGetStreamOutputRate( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_OUTPUT_RATE* pRate, + BOOL* pRepeat, + DXGI_RATIONAL* pCustomRate); + + void STDMETHODCALLTYPE VideoProcessorGetStreamSourceRect( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + RECT* pRect); + + void STDMETHODCALLTYPE VideoProcessorGetStreamDestRect( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + RECT* pRect); + + void STDMETHODCALLTYPE VideoProcessorGetStreamAlpha( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + FLOAT* pAlpha); + + void STDMETHODCALLTYPE VideoProcessorGetStreamPalette( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + UINT EntryCount, + UINT* pEntries); + + void STDMETHODCALLTYPE VideoProcessorGetStreamPixelAspectRatio( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + DXGI_RATIONAL* pSrcAspectRatio, + DXGI_RATIONAL* pDstAspectRatio); + + void STDMETHODCALLTYPE VideoProcessorGetStreamLumaKey( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + FLOAT* pLower, + FLOAT* pUpper); + + void STDMETHODCALLTYPE VideoProcessorGetStreamStereoFormat( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT* pFormat, + BOOL* pLeftViewFrame0, + BOOL* pBaseViewFrame0, + D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE* pFlipMode, + int* pMonoOffset); + + void STDMETHODCALLTYPE VideoProcessorGetStreamAutoProcessingMode( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnabled); + + void STDMETHODCALLTYPE VideoProcessorGetStreamFilter( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + D3D11_VIDEO_PROCESSOR_FILTER Filter, + BOOL* pEnabled, + int* pLevel); + + HRESULT STDMETHODCALLTYPE VideoProcessorGetStreamExtension( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + const GUID* pExtensionGuid, + UINT DataSize, + void* pData); + + void STDMETHODCALLTYPE VideoProcessorGetStreamRotation( + ID3D11VideoProcessor* pVideoProcessor, + UINT StreamIndex, + BOOL* pEnable, + D3D11_VIDEO_PROCESSOR_ROTATION* pRotation); + + HRESULT STDMETHODCALLTYPE VideoProcessorBlt( + ID3D11VideoProcessor* pVideoProcessor, + ID3D11VideoProcessorOutputView* pOutputView, + UINT FrameIdx, + UINT StreamCount, + const D3D11_VIDEO_PROCESSOR_STREAM* pStreams); + + HRESULT STDMETHODCALLTYPE NegotiateCryptoSessionKeyExchange( + ID3D11CryptoSession* pSession, + UINT DataSize, + void* pData); + + void STDMETHODCALLTYPE EncryptionBlt( + ID3D11CryptoSession* pSession, + ID3D11Texture2D* pSrcSurface, + ID3D11Texture2D* pDstSurface, + UINT IVSize, + void* pIV); + + void STDMETHODCALLTYPE DecryptionBlt( + ID3D11CryptoSession* pSession, + ID3D11Texture2D* pSrcSurface, + ID3D11Texture2D* pDstSurface, + D3D11_ENCRYPTED_BLOCK_INFO* pBlockInfo, + UINT KeySize, + const void* pKey, + UINT IVSize, + void* pIV); + + void STDMETHODCALLTYPE StartSessionKeyRefresh( + ID3D11CryptoSession* pSession, + UINT RandomNumberSize, + void* pRandomNumber); + + void STDMETHODCALLTYPE FinishSessionKeyRefresh( + ID3D11CryptoSession* pSession); + + HRESULT STDMETHODCALLTYPE GetEncryptionBltKey( + ID3D11CryptoSession* pSession, + UINT KeySize, + void* pKey); + + HRESULT STDMETHODCALLTYPE NegotiateAuthenticatedChannelKeyExchange( + ID3D11AuthenticatedChannel* pChannel, + UINT DataSize, + void* pData); + + HRESULT STDMETHODCALLTYPE QueryAuthenticatedChannel( + ID3D11AuthenticatedChannel* pChannel, + UINT InputSize, + const void* pInput, + UINT OutputSize, + void* pOutput); + + HRESULT STDMETHODCALLTYPE ConfigureAuthenticatedChannel( + ID3D11AuthenticatedChannel* pChannel, + UINT InputSize, + const void* pInput, + D3D11_AUTHENTICATED_CONFIGURE_OUTPUT* pOutput); + + private: + + struct alignas(16) UboData { + float colorMatrix[3][4]; + float coordMatrix[3][2]; + float yMin, yMax; + }; + + D3D11ImmediateContext* m_ctx; + + Rc<DxvkSampler> m_sampler; + Rc<DxvkShader> m_vs; + Rc<DxvkShader> m_fs; + Rc<DxvkBuffer> m_ubo; + + VkExtent2D m_dstExtent = { 0u, 0u }; + + void ApplyColorMatrix(float pDst[3][4], const float pSrc[3][4]); + + void ApplyYCbCrMatrix(float pColorMatrix[3][4], bool UseBt709); + + void BindOutputView( + ID3D11VideoProcessorOutputView* pOutputView); + + void BlitStream( + const D3D11VideoProcessorStreamState* pStreamState, + const D3D11_VIDEO_PROCESSOR_STREAM* pStream); + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view.h new file mode 100644 index 00000000..50fcef10 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view.h @@ -0,0 +1,81 @@ +#pragma once + +#include "d3d11_include.h" + +namespace dxvk { + + /** + * \brief Buffer view info + * + * Stores the byte range covered + * by a buffer view. + */ + struct D3D11_VK_BUFFER_VIEW_INFO { + VkDeviceSize Offset; + VkDeviceSize Length; + }; + + /** + * \brief Image view info + * + * Stores the subresource range + * covered by an image view. + */ + struct D3D11_VK_IMAGE_VIEW_INFO { + VkImageAspectFlags Aspects; + uint32_t MinLevel; + uint32_t MinLayer; + uint32_t NumLevels; + uint32_t NumLayers; + }; + + /** + * \brief Common view info + * + * Stores a pointer to the resource as + * well as the type-specific range that + * is affected by the view. + */ + struct D3D11_VK_VIEW_INFO { + ID3D11Resource* pResource; + D3D11_RESOURCE_DIMENSION Dimension; + UINT BindFlags; + union { + D3D11_VK_BUFFER_VIEW_INFO Buffer; + D3D11_VK_IMAGE_VIEW_INFO Image; + }; + }; + + /** + * \brief Checks whether two views overlap + * + * Overlapping views may conflict in case + * one or both views are used for writing. + * \param [in] a First view to check + * \param [in] b Second view to check + * \returns \c true if the views overlap + */ + inline bool CheckViewOverlap(const D3D11_VK_VIEW_INFO& a, const D3D11_VK_VIEW_INFO b) { + if (likely(a.pResource != b.pResource)) + return false; + + if (a.Dimension == D3D11_RESOURCE_DIMENSION_BUFFER) { + // Just check whether the buffer ranges overlap + return (a.Buffer.Offset < b.Buffer.Offset + b.Buffer.Length) + && (a.Buffer.Offset + a.Buffer.Length > b.Buffer.Offset); + } else { + // Check whether the subresource ranges overlap + return (a.Image.Aspects & b.Image.Aspects) + && (a.Image.MinLevel < b.Image.MinLevel + b.Image.NumLevels) + && (a.Image.MinLayer < b.Image.MinLayer + b.Image.NumLayers) + && (a.Image.MinLevel + a.Image.NumLevels > b.Image.MinLevel) + && (a.Image.MinLayer + a.Image.NumLayers > b.Image.MinLayer); + } + } + + template<typename T1, typename T2> + bool CheckViewOverlap(const T1* a, const T2* b) { + return a && b && CheckViewOverlap(a->GetViewInfo(), b->GetViewInfo()); + } + +}
\ No newline at end of file diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.cpp new file mode 100644 index 00000000..f0520c64 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.cpp @@ -0,0 +1,280 @@ +#include "d3d11_device.h" +#include "d3d11_buffer.h" +#include "d3d11_resource.h" +#include "d3d11_texture.h" +#include "d3d11_view_dsv.h" + +namespace dxvk { + + D3D11DepthStencilView::D3D11DepthStencilView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) + : D3D11DeviceChild<ID3D11DepthStencilView>(pDevice), + m_resource(pResource), m_desc(*pDesc), m_d3d10(this) { + ResourceAddRefPrivate(m_resource); + + D3D11_COMMON_RESOURCE_DESC resourceDesc; + GetCommonResourceDesc(pResource, &resourceDesc); + + DxvkImageViewCreateInfo viewInfo; + viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_DEPTH).Format; + viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask; + viewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + switch (pDesc->ViewDimension) { + case D3D11_DSV_DIMENSION_TEXTURE1D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_1D; + viewInfo.minLevel = pDesc->Texture1D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY; + viewInfo.minLevel = pDesc->Texture1DArray.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture1DArray.ArraySize; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = pDesc->Texture2D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = pDesc->Texture2DArray.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture2DArray.ArraySize; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMS: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize; + break; + + default: + throw DxvkError("D3D11: Invalid view dimension for DSV"); + } + + // Normalize view type so that we won't accidentally + // bind 2D array views and 2D views at the same time + if (viewInfo.numLayers == 1) { + if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D; + if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + } + + // Populate view info struct + m_info.pResource = pResource; + m_info.Dimension = resourceDesc.Dim; + m_info.BindFlags = resourceDesc.BindFlags; + m_info.Image.Aspects = viewInfo.aspect; + m_info.Image.MinLevel = viewInfo.minLevel; + m_info.Image.MinLayer = viewInfo.minLayer; + m_info.Image.NumLevels = viewInfo.numLevels; + m_info.Image.NumLayers = viewInfo.numLayers; + + if (m_desc.Flags & D3D11_DSV_READ_ONLY_DEPTH) + m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_DEPTH_BIT; + + if (m_desc.Flags & D3D11_DSV_READ_ONLY_STENCIL) + m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_STENCIL_BIT; + + // Create the underlying image view object + m_view = pDevice->GetDXVKDevice()->createImageView( + GetCommonTexture(pResource)->GetImage(), viewInfo); + } + + + D3D11DepthStencilView::~D3D11DepthStencilView() { + ResourceReleasePrivate(m_resource); + } + + + HRESULT STDMETHODCALLTYPE D3D11DepthStencilView::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11View) + || riid == __uuidof(ID3D11DepthStencilView)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10View) + || riid == __uuidof(ID3D10DepthStencilView)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11DepthStencilView::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11DepthStencilView::GetResource(ID3D11Resource** ppResource) { + *ppResource = ref(m_resource); + } + + + void STDMETHODCALLTYPE D3D11DepthStencilView::GetDesc(D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) { + *pDesc = m_desc; + } + + + HRESULT D3D11DepthStencilView::GetDescFromResource( + ID3D11Resource* pResource, + D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + pDesc->Flags = 0; + + switch (resourceDim) { + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC resourceDesc; + static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1D; + pDesc->Texture1D.MipSlice = 0; + } else { + pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1DARRAY; + pDesc->Texture1DArray.MipSlice = 0; + pDesc->Texture1DArray.FirstArraySlice = 0; + pDesc->Texture1DArray.ArraySize = resourceDesc.ArraySize; + } + } return S_OK; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC resourceDesc; + static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + + if (resourceDesc.SampleDesc.Count == 1) { + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + pDesc->Texture2D.MipSlice = 0; + } else { + pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + pDesc->Texture2DArray.MipSlice = 0; + pDesc->Texture2DArray.FirstArraySlice = 0; + pDesc->Texture2DArray.ArraySize = resourceDesc.ArraySize; + } + } else { + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + } else { + pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; + pDesc->Texture2DMSArray.FirstArraySlice = 0; + pDesc->Texture2DMSArray.ArraySize = resourceDesc.ArraySize; + } + } + } return S_OK; + + default: + Logger::err(str::format( + "D3D11: Unsupported dimension for depth stencil view: ", + resourceDim)); + return E_INVALIDARG; + } + } + + + HRESULT D3D11DepthStencilView::NormalizeDesc( + ID3D11Resource* pResource, + D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + uint32_t numLayers = 0; + + switch (resourceDim) { + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC resourceDesc; + static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE1D + && pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE1DARRAY) { + Logger::err("D3D11: Incompatible view dimension for Texture1D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + numLayers = resourceDesc.ArraySize; + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC resourceDesc; + static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE2D + && pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE2DARRAY + && pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE2DMS + && pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY) { + Logger::err("D3D11: Incompatible view dimension for Texture2D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + numLayers = resourceDesc.ArraySize; + } break; + + default: + return E_INVALIDARG; + } + + if (pDesc->Format == DXGI_FORMAT_UNKNOWN) + pDesc->Format = format; + + switch (pDesc->ViewDimension) { + case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: + if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice) + pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: + if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice) + pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: + if (pDesc->Texture2DMSArray.ArraySize > numLayers - pDesc->Texture2DMSArray.FirstArraySlice) + pDesc->Texture2DMSArray.ArraySize = numLayers - pDesc->Texture2DMSArray.FirstArraySlice; + break; + + default: + break; + } + + return S_OK; + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.h new file mode 100644 index 00000000..41b6fcb1 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.h @@ -0,0 +1,98 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_view_dsv.h" + +#include "d3d11_device_child.h" +#include "d3d11_view.h" + +namespace dxvk { + + class D3D11Device; + + /** + * \brief Depth-stencil view + * + * Unordered access views are special in that they can + * have counters, which can be used inside shaders to + * atomically append or consume structures. + */ + class D3D11DepthStencilView : public D3D11DeviceChild<ID3D11DepthStencilView> { + + public: + + D3D11DepthStencilView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc); + + ~D3D11DepthStencilView(); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final; + + void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final; + + void STDMETHODCALLTYPE GetDesc(D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) final; + + const D3D11_VK_VIEW_INFO& GetViewInfo() const { + return m_info; + } + + D3D11_RESOURCE_DIMENSION GetResourceType() const { + D3D11_RESOURCE_DIMENSION type; + m_resource->GetType(&type); + return type; + } + + Rc<DxvkImageView> GetImageView() const { + return m_view; + } + + VkImageLayout GetRenderLayout() const { + if (m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL) { + switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) { + default: // case 0 + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + case D3D11_DSV_READ_ONLY_DEPTH: + return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR; + case D3D11_DSV_READ_ONLY_STENCIL: + return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR; + case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL: + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } + } else { + return VK_IMAGE_LAYOUT_GENERAL; + } + } + + VkImageAspectFlags GetWritableAspectMask() const { + VkImageAspectFlags mask = m_view->formatInfo()->aspectMask; + if (m_desc.Flags & D3D11_DSV_READ_ONLY_DEPTH) mask &= ~VK_IMAGE_ASPECT_DEPTH_BIT; + if (m_desc.Flags & D3D11_DSV_READ_ONLY_STENCIL) mask &= ~VK_IMAGE_ASPECT_STENCIL_BIT; + return mask; + } + + D3D10DepthStencilView* GetD3D10Iface() { + return &m_d3d10; + } + + static HRESULT GetDescFromResource( + ID3D11Resource* pResource, + D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc); + + static HRESULT NormalizeDesc( + ID3D11Resource* pResource, + D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc); + + private: + + ID3D11Resource* m_resource; + D3D11_DEPTH_STENCIL_VIEW_DESC m_desc; + D3D11_VK_VIEW_INFO m_info; + Rc<DxvkImageView> m_view; + D3D10DepthStencilView m_d3d10; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.cpp new file mode 100644 index 00000000..86460502 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.cpp @@ -0,0 +1,440 @@ +#include "d3d11_device.h" +#include "d3d11_buffer.h" +#include "d3d11_resource.h" +#include "d3d11_texture.h" +#include "d3d11_view_rtv.h" + +namespace dxvk { + + D3D11RenderTargetView::D3D11RenderTargetView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) + : D3D11DeviceChild<ID3D11RenderTargetView1>(pDevice), + m_resource(pResource), m_desc(*pDesc), m_d3d10(this) { + ResourceAddRefPrivate(m_resource); + + auto texture = GetCommonTexture(pResource); + + D3D11_COMMON_RESOURCE_DESC resourceDesc; + GetCommonResourceDesc(pResource, &resourceDesc); + + DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat( + pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR); + + DxvkImageViewCreateInfo viewInfo; + viewInfo.format = formatInfo.Format; + viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask; + viewInfo.swizzle = formatInfo.Swizzle; + viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + switch (pDesc->ViewDimension) { + case D3D11_RTV_DIMENSION_TEXTURE1D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_1D; + viewInfo.minLevel = pDesc->Texture1D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY; + viewInfo.minLevel = pDesc->Texture1DArray.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture1DArray.ArraySize; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = pDesc->Texture2D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = pDesc->Texture2DArray.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture2DArray.ArraySize; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize; + break; + + case D3D11_RTV_DIMENSION_TEXTURE3D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = pDesc->Texture3D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture3D.FirstWSlice; + viewInfo.numLayers = pDesc->Texture3D.WSize; + break; + + default: + throw DxvkError("D3D11: Invalid view dimension for RTV"); + } + + if (texture->GetPlaneCount() > 1) + viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc)); + + // Normalize view type so that we won't accidentally + // bind 2D array views and 2D views at the same time + if (viewInfo.numLayers == 1) { + if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D; + if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + } + + // Populate view info struct + m_info.pResource = pResource; + m_info.Dimension = resourceDesc.Dim; + m_info.BindFlags = resourceDesc.BindFlags; + m_info.Image.Aspects = viewInfo.aspect; + m_info.Image.MinLevel = viewInfo.minLevel; + m_info.Image.MinLayer = viewInfo.minLayer; + m_info.Image.NumLevels = viewInfo.numLevels; + m_info.Image.NumLayers = viewInfo.numLayers; + + // Create the underlying image view object + m_view = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo); + } + + + D3D11RenderTargetView::~D3D11RenderTargetView() { + ResourceReleasePrivate(m_resource); + } + + + HRESULT STDMETHODCALLTYPE D3D11RenderTargetView::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11View) + || riid == __uuidof(ID3D11RenderTargetView) + || riid == __uuidof(ID3D11RenderTargetView1)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10View) + || riid == __uuidof(ID3D10RenderTargetView)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11RenderTargetView::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11RenderTargetView::GetResource(ID3D11Resource** ppResource) { + *ppResource = ref(m_resource); + } + + + void STDMETHODCALLTYPE D3D11RenderTargetView::GetDesc(D3D11_RENDER_TARGET_VIEW_DESC* pDesc) { + pDesc->Format = m_desc.Format; + pDesc->ViewDimension = m_desc.ViewDimension; + + switch (m_desc.ViewDimension) { + case D3D11_RTV_DIMENSION_UNKNOWN: + break; + + case D3D11_RTV_DIMENSION_BUFFER: + pDesc->Buffer = m_desc.Buffer; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1D: + pDesc->Texture1D = m_desc.Texture1D; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + pDesc->Texture1DArray = m_desc.Texture1DArray; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2D: + pDesc->Texture2D.MipSlice = m_desc.Texture2D.MipSlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + pDesc->Texture2DArray.MipSlice = m_desc.Texture2DArray.MipSlice; + pDesc->Texture2DArray.FirstArraySlice = m_desc.Texture2DArray.FirstArraySlice; + pDesc->Texture2DArray.ArraySize = m_desc.Texture2DArray.ArraySize; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + pDesc->Texture2DMS = m_desc.Texture2DMS; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + pDesc->Texture2DMSArray = m_desc.Texture2DMSArray; + break; + + case D3D11_RTV_DIMENSION_TEXTURE3D: + pDesc->Texture3D = m_desc.Texture3D; + break; + } + } + + + void STDMETHODCALLTYPE D3D11RenderTargetView::GetDesc1(D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) { + *pDesc = m_desc; + } + + + HRESULT D3D11RenderTargetView::GetDescFromResource( + ID3D11Resource* pResource, + D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + switch (resourceDim) { + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC resourceDesc; + static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D; + pDesc->Texture1D.MipSlice = 0; + } else { + pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY; + pDesc->Texture1DArray.MipSlice = 0; + pDesc->Texture1DArray.FirstArraySlice = 0; + pDesc->Texture1DArray.ArraySize = resourceDesc.ArraySize; + } + } return S_OK; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC resourceDesc; + static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + + if (resourceDesc.SampleDesc.Count == 1) { + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + pDesc->Texture2D.MipSlice = 0; + pDesc->Texture2D.PlaneSlice = 0; + } else { + pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + pDesc->Texture2DArray.MipSlice = 0; + pDesc->Texture2DArray.FirstArraySlice = 0; + pDesc->Texture2DArray.ArraySize = resourceDesc.ArraySize; + pDesc->Texture2DArray.PlaneSlice = 0; + } + } else { + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + } else { + pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; + pDesc->Texture2DMSArray.FirstArraySlice = 0; + pDesc->Texture2DMSArray.ArraySize = resourceDesc.ArraySize; + } + } + } return S_OK; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: { + D3D11_TEXTURE3D_DESC resourceDesc; + static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + pDesc->Texture3D.MipSlice = 0; + pDesc->Texture3D.FirstWSlice = 0; + pDesc->Texture3D.WSize = resourceDesc.Depth; + } return S_OK; + + default: + Logger::err(str::format( + "D3D11: Unsupported dimension for render target view: ", + resourceDim)); + return E_INVALIDARG; + } + } + + + D3D11_RENDER_TARGET_VIEW_DESC1 D3D11RenderTargetView::PromoteDesc( + const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, + UINT Plane) { + D3D11_RENDER_TARGET_VIEW_DESC1 dstDesc; + dstDesc.Format = pDesc->Format; + dstDesc.ViewDimension = pDesc->ViewDimension; + + switch (pDesc->ViewDimension) { + case D3D11_RTV_DIMENSION_UNKNOWN: + break; + + case D3D11_RTV_DIMENSION_BUFFER: + dstDesc.Buffer = pDesc->Buffer; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1D: + dstDesc.Texture1D = pDesc->Texture1D; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + dstDesc.Texture1DArray = pDesc->Texture1DArray; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2D: + dstDesc.Texture2D.MipSlice = pDesc->Texture2D.MipSlice; + dstDesc.Texture2D.PlaneSlice = Plane; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + dstDesc.Texture2DArray.MipSlice = pDesc->Texture2DArray.MipSlice; + dstDesc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice; + dstDesc.Texture2DArray.ArraySize = pDesc->Texture2DArray.ArraySize; + dstDesc.Texture2DArray.PlaneSlice = Plane; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + dstDesc.Texture2DMS = pDesc->Texture2DMS; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + dstDesc.Texture2DMSArray = pDesc->Texture2DMSArray; + break; + + case D3D11_RTV_DIMENSION_TEXTURE3D: + dstDesc.Texture3D = pDesc->Texture3D; + break; + } + + return dstDesc; + } + + + HRESULT D3D11RenderTargetView::NormalizeDesc( + ID3D11Resource* pResource, + D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + uint32_t numLayers = 0; + + switch (resourceDim) { + case D3D11_RESOURCE_DIMENSION_BUFFER: { + if (pDesc->ViewDimension != D3D11_RTV_DIMENSION_BUFFER) { + Logger::err("D3D11: Incompatible view dimension for Buffer"); + return E_INVALIDARG; + } + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC resourceDesc; + static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE1D + && pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE1DARRAY) { + Logger::err("D3D11: Incompatible view dimension for Texture1D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + numLayers = resourceDesc.ArraySize; + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC resourceDesc; + static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE2D + && pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE2DARRAY + && pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE2DMS + && pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY) { + Logger::err("D3D11: Incompatible view dimension for Texture2D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + numLayers = resourceDesc.ArraySize; + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: { + D3D11_TEXTURE3D_DESC resourceDesc; + static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE3D) { + Logger::err("D3D11: Incompatible view dimension for Texture3D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + numLayers = std::max(resourceDesc.Depth >> pDesc->Texture3D.MipSlice, 1u); + } break; + + default: + return E_INVALIDARG; + } + + if (pDesc->Format == DXGI_FORMAT_UNKNOWN) + pDesc->Format = format; + + switch (pDesc->ViewDimension) { + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice) + pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2D: + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice) + pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + if (pDesc->Texture2DMSArray.ArraySize > numLayers - pDesc->Texture2DMSArray.FirstArraySlice) + pDesc->Texture2DMSArray.ArraySize = numLayers - pDesc->Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE3D: + if (pDesc->Texture3D.WSize > numLayers - pDesc->Texture3D.FirstWSlice) + pDesc->Texture3D.WSize = numLayers - pDesc->Texture3D.FirstWSlice; + break; + + default: + break; + } + + return S_OK; + } + + + UINT D3D11RenderTargetView::GetPlaneSlice(const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) { + switch (pDesc->ViewDimension) { + case D3D11_RTV_DIMENSION_TEXTURE2D: + return pDesc->Texture2D.PlaneSlice; + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + return pDesc->Texture2DArray.PlaneSlice; + default: + return 0; + } + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.h new file mode 100644 index 00000000..080146ec --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.h @@ -0,0 +1,89 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_view_rtv.h" + +#include "d3d11_device_child.h" +#include "d3d11_view.h" + +namespace dxvk { + + class D3D11Device; + + /** + * \brief Render target view + */ + class D3D11RenderTargetView : public D3D11DeviceChild<ID3D11RenderTargetView1> { + + public: + + D3D11RenderTargetView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc); + + ~D3D11RenderTargetView(); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final; + + void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final; + + void STDMETHODCALLTYPE GetDesc(D3D11_RENDER_TARGET_VIEW_DESC* pDesc) final; + + void STDMETHODCALLTYPE GetDesc1(D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) final; + + const D3D11_VK_VIEW_INFO& GetViewInfo() const { + return m_info; + } + + BOOL HasBindFlag(UINT Flags) const { + return m_info.BindFlags & Flags; + } + + D3D11_RESOURCE_DIMENSION GetResourceType() const { + D3D11_RESOURCE_DIMENSION type; + m_resource->GetType(&type); + return type; + } + + Rc<DxvkImageView> GetImageView() const { + return m_view; + } + + VkImageLayout GetRenderLayout() const { + return m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL + ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + : VK_IMAGE_LAYOUT_GENERAL; + } + + D3D10RenderTargetView* GetD3D10Iface() { + return &m_d3d10; + } + + static HRESULT GetDescFromResource( + ID3D11Resource* pResource, + D3D11_RENDER_TARGET_VIEW_DESC1* pDesc); + + static D3D11_RENDER_TARGET_VIEW_DESC1 PromoteDesc( + const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, + UINT Plane); + + static HRESULT NormalizeDesc( + ID3D11Resource* pResource, + D3D11_RENDER_TARGET_VIEW_DESC1* pDesc); + + static UINT GetPlaneSlice( + const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc); + + private: + + ID3D11Resource* m_resource; + D3D11_RENDER_TARGET_VIEW_DESC1 m_desc; + D3D11_VK_VIEW_INFO m_info; + Rc<DxvkImageView> m_view; + D3D10RenderTargetView m_d3d10; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.cpp new file mode 100644 index 00000000..1c3d4d8d --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.cpp @@ -0,0 +1,592 @@ +#include "d3d11_device.h" +#include "d3d11_buffer.h" +#include "d3d11_resource.h" +#include "d3d11_texture.h" +#include "d3d11_view_srv.h" + +namespace dxvk { + + D3D11ShaderResourceView::D3D11ShaderResourceView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) + : D3D11DeviceChild<ID3D11ShaderResourceView1>(pDevice), + m_resource(pResource), m_desc(*pDesc), m_d3d10(this) { + ResourceAddRefPrivate(m_resource); + + D3D11_COMMON_RESOURCE_DESC resourceDesc; + GetCommonResourceDesc(pResource, &resourceDesc); + + // Basic view resource info + m_info.pResource = pResource; + m_info.Dimension = resourceDesc.Dim; + m_info.BindFlags = resourceDesc.BindFlags; + + if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) { + auto buffer = static_cast<D3D11Buffer*>(pResource); + + // Move buffer description to a common struct to + // avoid having to handle the two cases separately + D3D11_BUFFEREX_SRV bufInfo; + + if (pDesc->ViewDimension == D3D11_SRV_DIMENSION_BUFFEREX) { + bufInfo.FirstElement = pDesc->BufferEx.FirstElement; + bufInfo.NumElements = pDesc->BufferEx.NumElements; + bufInfo.Flags = pDesc->BufferEx.Flags; + } else if (pDesc->ViewDimension == D3D11_SRV_DIMENSION_BUFFER) { + bufInfo.FirstElement = pDesc->Buffer.FirstElement; + bufInfo.NumElements = pDesc->Buffer.NumElements; + bufInfo.Flags = 0; + } else { + throw DxvkError("D3D11: Invalid view dimension for buffer SRV"); + } + + // Fill in buffer view info + DxvkBufferViewCreateInfo viewInfo; + + if (bufInfo.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) { + // Raw buffer view. We'll represent this as a + // uniform texel buffer with UINT32 elements. + viewInfo.format = VK_FORMAT_R32_UINT; + viewInfo.rangeOffset = sizeof(uint32_t) * bufInfo.FirstElement; + viewInfo.rangeLength = sizeof(uint32_t) * bufInfo.NumElements; + } else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) { + // Structured buffer view + viewInfo.format = VK_FORMAT_R32_UINT; + viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement; + viewInfo.rangeLength = buffer->Desc()->StructureByteStride * bufInfo.NumElements; + } else { + viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format; + + const DxvkFormatInfo* formatInfo = imageFormatInfo(viewInfo.format); + viewInfo.rangeOffset = formatInfo->elementSize * bufInfo.FirstElement; + viewInfo.rangeLength = formatInfo->elementSize * bufInfo.NumElements; + } + + // Populate view info struct + m_info.Buffer.Offset = viewInfo.rangeOffset; + m_info.Buffer.Length = viewInfo.rangeLength; + + // Create underlying buffer view object + m_bufferView = pDevice->GetDXVKDevice()->createBufferView( + buffer->GetBuffer(), viewInfo); + } else { + auto texture = GetCommonTexture(pResource); + auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode()); + + DxvkImageViewCreateInfo viewInfo; + viewInfo.format = formatInfo.Format; + viewInfo.aspect = formatInfo.Aspect; + viewInfo.swizzle = formatInfo.Swizzle; + viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + + // Shaders expect the stencil value in the G component + if (viewInfo.aspect == VK_IMAGE_ASPECT_STENCIL_BIT) { + viewInfo.swizzle = VkComponentMapping { + VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO }; + } + + switch (pDesc->ViewDimension) { + case D3D11_SRV_DIMENSION_TEXTURE1D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_1D; + viewInfo.minLevel = pDesc->Texture1D.MostDetailedMip; + viewInfo.numLevels = pDesc->Texture1D.MipLevels; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_SRV_DIMENSION_TEXTURE1DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY; + viewInfo.minLevel = pDesc->Texture1DArray.MostDetailedMip; + viewInfo.numLevels = pDesc->Texture1DArray.MipLevels; + viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture1DArray.ArraySize; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = pDesc->Texture2D.MostDetailedMip; + viewInfo.numLevels = pDesc->Texture2D.MipLevels; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = pDesc->Texture2DArray.MostDetailedMip; + viewInfo.numLevels = pDesc->Texture2DArray.MipLevels; + viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture2DArray.ArraySize; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DMS: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize; + break; + + case D3D11_SRV_DIMENSION_TEXTURE3D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_3D; + viewInfo.minLevel = pDesc->Texture3D.MostDetailedMip; + viewInfo.numLevels = pDesc->Texture3D.MipLevels; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBE: { + const bool cubeArraysEnabled = pDevice->GetDXVKDevice()->features().core.features.imageCubeArray; + viewInfo.type = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE; + viewInfo.minLevel = pDesc->TextureCube.MostDetailedMip; + viewInfo.numLevels = pDesc->TextureCube.MipLevels; + viewInfo.minLayer = 0; + viewInfo.numLayers = 6; + } break; + + case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + viewInfo.minLevel = pDesc->TextureCubeArray.MostDetailedMip; + viewInfo.numLevels = pDesc->TextureCubeArray.MipLevels; + viewInfo.minLayer = pDesc->TextureCubeArray.First2DArrayFace; + viewInfo.numLayers = pDesc->TextureCubeArray.NumCubes * 6; + break; + + default: + throw DxvkError("D3D11: Invalid view dimension for image SRV"); + } + + if (texture->GetPlaneCount() > 1) + viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc)); + + // Populate view info struct + m_info.Image.Aspects = viewInfo.aspect; + m_info.Image.MinLevel = viewInfo.minLevel; + m_info.Image.MinLayer = viewInfo.minLayer; + m_info.Image.NumLevels = viewInfo.numLevels; + m_info.Image.NumLayers = viewInfo.numLayers; + + // Create the underlying image view object + m_imageView = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo); + } + } + + + D3D11ShaderResourceView::~D3D11ShaderResourceView() { + ResourceReleasePrivate(m_resource); + } + + + HRESULT STDMETHODCALLTYPE D3D11ShaderResourceView::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11View) + || riid == __uuidof(ID3D11ShaderResourceView) + || riid == __uuidof(ID3D11ShaderResourceView1)) { + *ppvObject = ref(this); + return S_OK; + } + + if (riid == __uuidof(ID3D10DeviceChild) + || riid == __uuidof(ID3D10View) + || riid == __uuidof(ID3D10ShaderResourceView) + || riid == __uuidof(ID3D10ShaderResourceView1)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11ShaderResourceView::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11ShaderResourceView::GetResource(ID3D11Resource** ppResource) { + *ppResource = ref(m_resource); + } + + + void STDMETHODCALLTYPE D3D11ShaderResourceView::GetDesc(D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc) { + pDesc->Format = m_desc.Format; + pDesc->ViewDimension = m_desc.ViewDimension; + + switch (m_desc.ViewDimension) { + case D3D11_SRV_DIMENSION_UNKNOWN: + break; + + case D3D11_SRV_DIMENSION_BUFFER: + pDesc->Buffer = m_desc.Buffer; + break; + + case D3D11_SRV_DIMENSION_TEXTURE1D: + pDesc->Texture1D = m_desc.Texture1D; + break; + + case D3D11_SRV_DIMENSION_TEXTURE1DARRAY: + pDesc->Texture1DArray = m_desc.Texture1DArray; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2D: + pDesc->Texture2D.MostDetailedMip = m_desc.Texture2D.MostDetailedMip; + pDesc->Texture2D.MipLevels = m_desc.Texture2D.MipLevels; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + pDesc->Texture2DArray.MostDetailedMip = m_desc.Texture2DArray.MostDetailedMip; + pDesc->Texture2DArray.MipLevels = m_desc.Texture2DArray.MipLevels; + pDesc->Texture2DArray.FirstArraySlice = m_desc.Texture2DArray.FirstArraySlice; + pDesc->Texture2DArray.ArraySize = m_desc.Texture2DArray.ArraySize; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DMS: + pDesc->Texture2DMS = m_desc.Texture2DMS; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY: + pDesc->Texture2DMSArray = m_desc.Texture2DMSArray; + break; + + case D3D11_SRV_DIMENSION_TEXTURE3D: + pDesc->Texture3D = m_desc.Texture3D; + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBE: + pDesc->TextureCube = m_desc.TextureCube; + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY: + pDesc->TextureCubeArray = m_desc.TextureCubeArray; + break; + + case D3D11_SRV_DIMENSION_BUFFEREX: + pDesc->BufferEx = m_desc.BufferEx; + break; + } + } + + + void STDMETHODCALLTYPE D3D11ShaderResourceView::GetDesc1(D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) { + *pDesc = m_desc; + } + + + HRESULT D3D11ShaderResourceView::GetDescFromResource( + ID3D11Resource* pResource, + D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + switch (resourceDim) { + case D3D11_RESOURCE_DIMENSION_BUFFER: { + D3D11_BUFFER_DESC bufferDesc; + static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc); + + if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) { + pDesc->Format = DXGI_FORMAT_UNKNOWN; + pDesc->ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + pDesc->Buffer.FirstElement = 0; + pDesc->Buffer.NumElements = bufferDesc.ByteWidth / bufferDesc.StructureByteStride; + return S_OK; + } + } return E_INVALIDARG; + + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC resourceDesc; + static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D; + pDesc->Texture1D.MostDetailedMip = 0; + pDesc->Texture1D.MipLevels = resourceDesc.MipLevels; + } else { + pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY; + pDesc->Texture1DArray.MostDetailedMip = 0; + pDesc->Texture1DArray.MipLevels = resourceDesc.MipLevels; + pDesc->Texture1DArray.FirstArraySlice = 0; + pDesc->Texture1DArray.ArraySize = resourceDesc.ArraySize; + } + } return S_OK; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC resourceDesc; + static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + + if (resourceDesc.SampleDesc.Count == 1) { + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + pDesc->Texture2D.MostDetailedMip = 0; + pDesc->Texture2D.MipLevels = resourceDesc.MipLevels; + pDesc->Texture2D.PlaneSlice = 0; + } else { + pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + pDesc->Texture2DArray.MostDetailedMip = 0; + pDesc->Texture2DArray.MipLevels = resourceDesc.MipLevels; + pDesc->Texture2DArray.FirstArraySlice = 0; + pDesc->Texture2DArray.ArraySize = resourceDesc.ArraySize; + pDesc->Texture2DArray.PlaneSlice = 0; + } + } else { + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; + } else { + pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; + pDesc->Texture2DMSArray.FirstArraySlice = 0; + pDesc->Texture2DMSArray.ArraySize = resourceDesc.ArraySize; + } + } + } return S_OK; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: { + D3D11_TEXTURE3D_DESC resourceDesc; + static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + pDesc->Texture3D.MostDetailedMip = 0; + pDesc->Texture3D.MipLevels = resourceDesc.MipLevels; + } return S_OK; + + default: + Logger::err(str::format( + "D3D11: Unsupported dimension for shader resource view: ", + resourceDim)); + return E_INVALIDARG; + } + } + + + D3D11_SHADER_RESOURCE_VIEW_DESC1 D3D11ShaderResourceView::PromoteDesc( + const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, + UINT Plane) { + D3D11_SHADER_RESOURCE_VIEW_DESC1 dstDesc; + dstDesc.Format = pDesc->Format; + dstDesc.ViewDimension = pDesc->ViewDimension; + + switch (pDesc->ViewDimension) { + case D3D11_SRV_DIMENSION_UNKNOWN: + break; + + case D3D11_SRV_DIMENSION_BUFFER: + dstDesc.Buffer = pDesc->Buffer; + break; + + case D3D11_SRV_DIMENSION_TEXTURE1D: + dstDesc.Texture1D = pDesc->Texture1D; + break; + + case D3D11_SRV_DIMENSION_TEXTURE1DARRAY: + dstDesc.Texture1DArray = pDesc->Texture1DArray; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2D: + dstDesc.Texture2D.MostDetailedMip = pDesc->Texture2D.MostDetailedMip; + dstDesc.Texture2D.MipLevels = pDesc->Texture2D.MipLevels; + dstDesc.Texture2D.PlaneSlice = Plane; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + dstDesc.Texture2DArray.MostDetailedMip = pDesc->Texture2DArray.MostDetailedMip; + dstDesc.Texture2DArray.MipLevels = pDesc->Texture2DArray.MipLevels; + dstDesc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice; + dstDesc.Texture2DArray.ArraySize = pDesc->Texture2DArray.ArraySize; + dstDesc.Texture2DArray.PlaneSlice = Plane; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DMS: + dstDesc.Texture2DMS = pDesc->Texture2DMS; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY: + dstDesc.Texture2DMSArray = pDesc->Texture2DMSArray; + break; + + case D3D11_SRV_DIMENSION_TEXTURE3D: + dstDesc.Texture3D = pDesc->Texture3D; + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBE: + dstDesc.TextureCube = pDesc->TextureCube; + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY: + dstDesc.TextureCubeArray = pDesc->TextureCubeArray; + break; + + case D3D11_SRV_DIMENSION_BUFFEREX: + dstDesc.BufferEx = pDesc->BufferEx; + break; + } + + return dstDesc; + } + + + HRESULT D3D11ShaderResourceView::NormalizeDesc( + ID3D11Resource* pResource, + D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + uint32_t mipLevels = 0; + uint32_t numLayers = 0; + + switch (resourceDim) { + case D3D11_RESOURCE_DIMENSION_BUFFER: { + if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_BUFFER + && pDesc->ViewDimension != D3D11_SRV_DIMENSION_BUFFEREX) { + Logger::err("D3D11: Incompatible view dimension for Buffer"); + return E_INVALIDARG; + } + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC resourceDesc; + static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE1D + && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE1DARRAY) { + Logger::err("D3D11: Incompatible view dimension for Texture1D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + mipLevels = resourceDesc.MipLevels; + numLayers = resourceDesc.ArraySize; + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC resourceDesc; + static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2D + && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DARRAY + && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DMS + && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY + && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURECUBE + && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) { + Logger::err("D3D11: Incompatible view dimension for Texture2D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + mipLevels = resourceDesc.MipLevels; + numLayers = resourceDesc.ArraySize; + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: { + D3D11_TEXTURE3D_DESC resourceDesc; + static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE3D) { + Logger::err("D3D11: Incompatible view dimension for Texture3D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + mipLevels = resourceDesc.MipLevels; + numLayers = 1; + } break; + + default: + return E_INVALIDARG; + } + + if (pDesc->Format == DXGI_FORMAT_UNKNOWN) + pDesc->Format = format; + + switch (pDesc->ViewDimension) { + case D3D11_SRV_DIMENSION_BUFFER: + if (pDesc->Buffer.NumElements == 0) + return E_INVALIDARG; + break; + + case D3D11_SRV_DIMENSION_BUFFEREX: + if (pDesc->BufferEx.NumElements == 0) + return E_INVALIDARG; + break; + + case D3D11_SRV_DIMENSION_TEXTURE1D: + if (pDesc->Texture1D.MipLevels > mipLevels - pDesc->Texture1D.MostDetailedMip) + pDesc->Texture1D.MipLevels = mipLevels - pDesc->Texture1D.MostDetailedMip; + break; + + case D3D11_SRV_DIMENSION_TEXTURE1DARRAY: + if (pDesc->Texture1DArray.MipLevels > mipLevels - pDesc->Texture1DArray.MostDetailedMip) + pDesc->Texture1DArray.MipLevels = mipLevels - pDesc->Texture1DArray.MostDetailedMip; + if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice) + pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2D: + if (pDesc->Texture2D.MipLevels > mipLevels - pDesc->Texture2D.MostDetailedMip) + pDesc->Texture2D.MipLevels = mipLevels - pDesc->Texture2D.MostDetailedMip; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + if (pDesc->Texture2DArray.MipLevels > mipLevels - pDesc->Texture2DArray.MostDetailedMip) + pDesc->Texture2DArray.MipLevels = mipLevels - pDesc->Texture2DArray.MostDetailedMip; + if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice) + pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice; + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY: + if (pDesc->Texture2DMSArray.ArraySize > numLayers - pDesc->Texture2DMSArray.FirstArraySlice) + pDesc->Texture2DMSArray.ArraySize = numLayers - pDesc->Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBE: + if (pDesc->TextureCube.MipLevels > mipLevels - pDesc->TextureCube.MostDetailedMip) + pDesc->TextureCube.MipLevels = mipLevels - pDesc->TextureCube.MostDetailedMip; + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY: + if (pDesc->TextureCubeArray.MipLevels > mipLevels - pDesc->TextureCubeArray.MostDetailedMip) + pDesc->TextureCubeArray.MipLevels = mipLevels - pDesc->TextureCubeArray.MostDetailedMip; + if (pDesc->TextureCubeArray.NumCubes > (numLayers - pDesc->TextureCubeArray.First2DArrayFace) / 6) + pDesc->TextureCubeArray.NumCubes = (numLayers - pDesc->TextureCubeArray.First2DArrayFace) / 6; + break; + + case D3D11_SRV_DIMENSION_TEXTURE3D: + if (pDesc->Texture3D.MipLevels > mipLevels - pDesc->Texture3D.MostDetailedMip) + pDesc->Texture3D.MipLevels = mipLevels - pDesc->Texture3D.MostDetailedMip; + break; + + default: + break; + } + + return S_OK; + } + + + UINT D3D11ShaderResourceView::GetPlaneSlice(const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) { + switch (pDesc->ViewDimension) { + case D3D11_SRV_DIMENSION_TEXTURE2D: + return pDesc->Texture2D.PlaneSlice; + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + return pDesc->Texture2DArray.PlaneSlice; + default: + return 0; + } + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.h new file mode 100644 index 00000000..e7c5872e --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.h @@ -0,0 +1,94 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "../d3d10/d3d10_view_srv.h" + +#include "d3d11_device_child.h" +#include "d3d11_view.h" + +namespace dxvk { + + class D3D11Device; + + /** + * \brief Shader resource view + */ + class D3D11ShaderResourceView : public D3D11DeviceChild<ID3D11ShaderResourceView1> { + + public: + + D3D11ShaderResourceView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc); + + ~D3D11ShaderResourceView(); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final; + + void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final; + + void STDMETHODCALLTYPE GetDesc(D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc) final; + + void STDMETHODCALLTYPE GetDesc1(D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) final; + + const D3D11_VK_VIEW_INFO& GetViewInfo() const { + return m_info; + } + + BOOL TestHazards() const { + return m_info.BindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_UNORDERED_ACCESS); + } + + D3D11_RESOURCE_DIMENSION GetResourceType() const { + D3D11_RESOURCE_DIMENSION type; + m_resource->GetType(&type); + return type; + } + + D3D11_COMMON_RESOURCE_DESC GetResourceDesc() const { + D3D11_COMMON_RESOURCE_DESC desc; + GetCommonResourceDesc(m_resource, &desc); + return desc; + } + + Rc<DxvkBufferView> GetBufferView() const { + return m_bufferView; + } + + Rc<DxvkImageView> GetImageView() const { + return m_imageView; + } + + D3D10ShaderResourceView* GetD3D10Iface() { + return &m_d3d10; + } + + static HRESULT GetDescFromResource( + ID3D11Resource* pResource, + D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc); + + static D3D11_SHADER_RESOURCE_VIEW_DESC1 PromoteDesc( + const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, + UINT Plane); + + static HRESULT NormalizeDesc( + ID3D11Resource* pResource, + D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc); + + static UINT GetPlaneSlice( + const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc); + + private: + + ID3D11Resource* m_resource; + D3D11_SHADER_RESOURCE_VIEW_DESC1 m_desc; + D3D11_VK_VIEW_INFO m_info; + Rc<DxvkBufferView> m_bufferView; + Rc<DxvkImageView> m_imageView; + D3D10ShaderResourceView m_d3d10; + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.cpp new file mode 100644 index 00000000..54f826e7 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.cpp @@ -0,0 +1,447 @@ +#include "d3d11_device.h" +#include "d3d11_buffer.h" +#include "d3d11_resource.h" +#include "d3d11_texture.h" +#include "d3d11_view_uav.h" + +namespace dxvk { + + D3D11UnorderedAccessView::D3D11UnorderedAccessView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) + : D3D11DeviceChild<ID3D11UnorderedAccessView1>(pDevice), + m_resource(pResource), m_desc(*pDesc) { + ResourceAddRefPrivate(m_resource); + + D3D11_COMMON_RESOURCE_DESC resourceDesc; + GetCommonResourceDesc(pResource, &resourceDesc); + + // Basic view resource info + m_info.pResource = pResource; + m_info.Dimension = resourceDesc.Dim; + m_info.BindFlags = resourceDesc.BindFlags; + + if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) { + auto buffer = static_cast<D3D11Buffer*>(pResource); + + DxvkBufferViewCreateInfo viewInfo; + + if (pDesc->Buffer.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) { + viewInfo.format = VK_FORMAT_R32_UINT; + viewInfo.rangeOffset = sizeof(uint32_t) * pDesc->Buffer.FirstElement; + viewInfo.rangeLength = sizeof(uint32_t) * pDesc->Buffer.NumElements; + } else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) { + viewInfo.format = VK_FORMAT_R32_UINT; + viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * pDesc->Buffer.FirstElement; + viewInfo.rangeLength = buffer->Desc()->StructureByteStride * pDesc->Buffer.NumElements; + } else { + viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format; + + const DxvkFormatInfo* formatInfo = imageFormatInfo(viewInfo.format); + viewInfo.rangeOffset = formatInfo->elementSize * pDesc->Buffer.FirstElement; + viewInfo.rangeLength = formatInfo->elementSize * pDesc->Buffer.NumElements; + } + + if (pDesc->Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER)) + m_counterBuffer = CreateCounterBuffer(); + + // Populate view info struct + m_info.Buffer.Offset = viewInfo.rangeOffset; + m_info.Buffer.Length = viewInfo.rangeLength; + + m_bufferView = pDevice->GetDXVKDevice()->createBufferView( + buffer->GetBuffer(), viewInfo); + } else { + auto texture = GetCommonTexture(pResource); + auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode()); + + DxvkImageViewCreateInfo viewInfo; + viewInfo.format = formatInfo.Format; + viewInfo.aspect = formatInfo.Aspect; + viewInfo.swizzle = formatInfo.Swizzle; + viewInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT; + + switch (pDesc->ViewDimension) { + case D3D11_UAV_DIMENSION_TEXTURE1D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_1D; + viewInfo.minLevel = pDesc->Texture1D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_UAV_DIMENSION_TEXTURE1DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY; + viewInfo.minLevel = pDesc->Texture1DArray.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture1DArray.ArraySize; + break; + + case D3D11_UAV_DIMENSION_TEXTURE2D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = pDesc->Texture2D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_UAV_DIMENSION_TEXTURE2DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = pDesc->Texture2DArray.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice; + viewInfo.numLayers = pDesc->Texture2DArray.ArraySize; + break; + + case D3D11_UAV_DIMENSION_TEXTURE3D: + // FIXME we actually have to map this to a + // 2D array view in order to support W slices + viewInfo.type = VK_IMAGE_VIEW_TYPE_3D; + viewInfo.minLevel = pDesc->Texture3D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + default: + throw DxvkError("D3D11: Invalid view dimension for image UAV"); + } + + if (texture->GetPlaneCount() > 1) + viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc)); + + // Populate view info struct + m_info.Image.Aspects = viewInfo.aspect; + m_info.Image.MinLevel = viewInfo.minLevel; + m_info.Image.MinLayer = viewInfo.minLayer; + m_info.Image.NumLevels = viewInfo.numLevels; + m_info.Image.NumLayers = viewInfo.numLayers; + + m_imageView = pDevice->GetDXVKDevice()->createImageView( + GetCommonTexture(pResource)->GetImage(), viewInfo); + } + } + + + D3D11UnorderedAccessView::~D3D11UnorderedAccessView() { + ResourceReleasePrivate(m_resource); + } + + + HRESULT STDMETHODCALLTYPE D3D11UnorderedAccessView::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(ID3D11DeviceChild) + || riid == __uuidof(ID3D11View) + || riid == __uuidof(ID3D11UnorderedAccessView) + || riid == __uuidof(ID3D11UnorderedAccessView1)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D11UnorderedAccessView::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetResource(ID3D11Resource** ppResource) { + *ppResource = ref(m_resource); + } + + + void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetDesc(D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc) { + pDesc->Format = m_desc.Format; + pDesc->ViewDimension = m_desc.ViewDimension; + + switch (m_desc.ViewDimension) { + case D3D11_UAV_DIMENSION_UNKNOWN: + break; + + case D3D11_UAV_DIMENSION_BUFFER: + pDesc->Buffer = m_desc.Buffer; + break; + + case D3D11_UAV_DIMENSION_TEXTURE1D: + pDesc->Texture1D = m_desc.Texture1D; + break; + + case D3D11_UAV_DIMENSION_TEXTURE1DARRAY: + pDesc->Texture1DArray = m_desc.Texture1DArray; + break; + + case D3D11_UAV_DIMENSION_TEXTURE2D: + pDesc->Texture2D.MipSlice = m_desc.Texture2D.MipSlice; + break; + + case D3D11_UAV_DIMENSION_TEXTURE2DARRAY: + pDesc->Texture2DArray.MipSlice = m_desc.Texture2DArray.MipSlice; + pDesc->Texture2DArray.FirstArraySlice = m_desc.Texture2DArray.FirstArraySlice; + pDesc->Texture2DArray.ArraySize = m_desc.Texture2DArray.ArraySize; + break; + + case D3D11_UAV_DIMENSION_TEXTURE3D: + pDesc->Texture3D = m_desc.Texture3D; + break; + } + } + + + void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetDesc1(D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) { + *pDesc = m_desc; + } + + + HRESULT D3D11UnorderedAccessView::GetDescFromResource( + ID3D11Resource* pResource, + D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + switch (resourceDim) { + case D3D11_RESOURCE_DIMENSION_BUFFER: { + D3D11_BUFFER_DESC bufferDesc; + static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc); + + if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) { + pDesc->Format = DXGI_FORMAT_UNKNOWN; + pDesc->ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + pDesc->Buffer.FirstElement = 0; + pDesc->Buffer.NumElements = bufferDesc.ByteWidth / bufferDesc.StructureByteStride; + pDesc->Buffer.Flags = 0; + return S_OK; + } + } return E_INVALIDARG; + + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC resourceDesc; + static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1D; + pDesc->Texture1D.MipSlice = 0; + } else { + pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1DARRAY; + pDesc->Texture1DArray.MipSlice = 0; + pDesc->Texture1DArray.FirstArraySlice = 0; + pDesc->Texture1DArray.ArraySize = resourceDesc.ArraySize; + } + } return S_OK; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC resourceDesc; + static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + + if (resourceDesc.ArraySize == 1) { + pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + pDesc->Texture2D.MipSlice = 0; + pDesc->Texture2D.PlaneSlice = 0; + } else { + pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY; + pDesc->Texture2DArray.MipSlice = 0; + pDesc->Texture2DArray.FirstArraySlice = 0; + pDesc->Texture2DArray.ArraySize = resourceDesc.ArraySize; + pDesc->Texture2DArray.PlaneSlice = 0; + } + } return S_OK; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: { + D3D11_TEXTURE3D_DESC resourceDesc; + static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc); + + pDesc->Format = resourceDesc.Format; + pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D; + pDesc->Texture3D.MipSlice = 0; + pDesc->Texture3D.WSize = resourceDesc.Depth; + } return S_OK; + + default: + Logger::err(str::format( + "D3D11: Unsupported dimension for unordered access view: ", + resourceDim)); + return E_INVALIDARG; + } + } + + + D3D11_UNORDERED_ACCESS_VIEW_DESC1 D3D11UnorderedAccessView::PromoteDesc( + const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, + UINT Plane) { + D3D11_UNORDERED_ACCESS_VIEW_DESC1 dstDesc; + dstDesc.Format = pDesc->Format; + dstDesc.ViewDimension = pDesc->ViewDimension; + + switch (pDesc->ViewDimension) { + case D3D11_UAV_DIMENSION_UNKNOWN: + break; + + case D3D11_UAV_DIMENSION_BUFFER: + dstDesc.Buffer = pDesc->Buffer; + break; + + case D3D11_UAV_DIMENSION_TEXTURE1D: + dstDesc.Texture1D = pDesc->Texture1D; + break; + + case D3D11_UAV_DIMENSION_TEXTURE1DARRAY: + dstDesc.Texture1DArray = pDesc->Texture1DArray; + break; + + case D3D11_UAV_DIMENSION_TEXTURE2D: + dstDesc.Texture2D.MipSlice = pDesc->Texture2D.MipSlice; + dstDesc.Texture2D.PlaneSlice = Plane; + break; + + case D3D11_UAV_DIMENSION_TEXTURE2DARRAY: + dstDesc.Texture2DArray.MipSlice = pDesc->Texture2DArray.MipSlice; + dstDesc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice; + dstDesc.Texture2DArray.ArraySize = pDesc->Texture2DArray.ArraySize; + dstDesc.Texture2DArray.PlaneSlice = Plane; + break; + + case D3D11_UAV_DIMENSION_TEXTURE3D: + dstDesc.Texture3D = pDesc->Texture3D; + break; + } + + return dstDesc; + } + + + HRESULT D3D11UnorderedAccessView::NormalizeDesc( + ID3D11Resource* pResource, + D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) { + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + uint32_t numLayers = 0; + + switch (resourceDim) { + case D3D11_RESOURCE_DIMENSION_BUFFER: { + if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_BUFFER) { + Logger::err("D3D11: Incompatible view dimension for Buffer"); + return E_INVALIDARG; + } + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE1D: { + D3D11_TEXTURE1D_DESC resourceDesc; + static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE1D + && pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE1DARRAY) { + Logger::err("D3D11: Incompatible view dimension for Texture1D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + numLayers = resourceDesc.ArraySize; + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: { + D3D11_TEXTURE2D_DESC resourceDesc; + static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE2D + && pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE2DARRAY) { + Logger::err("D3D11: Incompatible view dimension for Texture2D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + numLayers = resourceDesc.ArraySize; + } break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: { + D3D11_TEXTURE3D_DESC resourceDesc; + static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc); + + if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE3D) { + Logger::err("D3D11: Incompatible view dimension for Texture3D"); + return E_INVALIDARG; + } + + format = resourceDesc.Format; + numLayers = std::max(resourceDesc.Depth >> pDesc->Texture3D.MipSlice, 1u); + } break; + + default: + return E_INVALIDARG; + } + + if (pDesc->Format == DXGI_FORMAT_UNKNOWN) + pDesc->Format = format; + + switch (pDesc->ViewDimension) { + case D3D11_UAV_DIMENSION_BUFFER: + if (pDesc->Buffer.NumElements == 0) + return E_INVALIDARG; + break; + + case D3D11_UAV_DIMENSION_TEXTURE1DARRAY: + if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice) + pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice; + break; + + case D3D11_UAV_DIMENSION_TEXTURE2D: + break; + + case D3D11_UAV_DIMENSION_TEXTURE2DARRAY: + if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice) + pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice; + break; + + case D3D11_UAV_DIMENSION_TEXTURE3D: + if (pDesc->Texture3D.WSize > numLayers - pDesc->Texture3D.FirstWSlice) + pDesc->Texture3D.WSize = numLayers - pDesc->Texture3D.FirstWSlice; + break; + + default: + break; + } + + return S_OK; + } + + + UINT D3D11UnorderedAccessView::GetPlaneSlice(const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) { + switch (pDesc->ViewDimension) { + case D3D11_UAV_DIMENSION_TEXTURE2D: + return pDesc->Texture2D.PlaneSlice; + case D3D11_UAV_DIMENSION_TEXTURE2DARRAY: + return pDesc->Texture2DArray.PlaneSlice; + default: + return 0; + } + } + + + Rc<DxvkBuffer> D3D11UnorderedAccessView::CreateCounterBuffer() { + Rc<DxvkDevice> device = m_parent->GetDXVKDevice(); + + DxvkBufferCreateInfo info; + info.size = sizeof(uint32_t); + info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT + | device->getShaderPipelineStages(); + info.access = VK_ACCESS_TRANSFER_WRITE_BIT + | VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_SHADER_WRITE_BIT + | VK_ACCESS_SHADER_READ_BIT; + return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.h new file mode 100644 index 00000000..3076fe09 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.h @@ -0,0 +1,94 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +#include "d3d11_device_child.h" +#include "d3d11_view.h" + +namespace dxvk { + + class D3D11Device; + + /** + * \brief Unordered access view + * + * Unordered access views are special in that they can + * have counters, which can be used inside shaders to + * atomically append or consume structures. + */ + class D3D11UnorderedAccessView : public D3D11DeviceChild<ID3D11UnorderedAccessView1> { + + public: + + D3D11UnorderedAccessView( + D3D11Device* pDevice, + ID3D11Resource* pResource, + const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc); + + ~D3D11UnorderedAccessView(); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final; + + void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final; + + void STDMETHODCALLTYPE GetDesc(D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc) final; + + void STDMETHODCALLTYPE GetDesc1(D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) final; + + const D3D11_VK_VIEW_INFO& GetViewInfo() const { + return m_info; + } + + BOOL HasBindFlag(UINT Flags) const { + return m_info.BindFlags & Flags; + } + + D3D11_RESOURCE_DIMENSION GetResourceType() const { + D3D11_RESOURCE_DIMENSION type; + m_resource->GetType(&type); + return type; + } + + Rc<DxvkBufferView> GetBufferView() const { + return m_bufferView; + } + + Rc<DxvkImageView> GetImageView() const { + return m_imageView; + } + + DxvkBufferSlice GetCounterSlice() const { + return m_counterBuffer != nullptr + ? DxvkBufferSlice(m_counterBuffer) + : DxvkBufferSlice(); + } + + static HRESULT GetDescFromResource( + ID3D11Resource* pResource, + D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc); + + static D3D11_UNORDERED_ACCESS_VIEW_DESC1 PromoteDesc( + const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, + UINT Plane); + + static HRESULT NormalizeDesc( + ID3D11Resource* pResource, + D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc); + + static UINT GetPlaneSlice( + const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc); + + private: + + ID3D11Resource* m_resource; + D3D11_UNORDERED_ACCESS_VIEW_DESC1 m_desc; + D3D11_VK_VIEW_INFO m_info; + Rc<DxvkBufferView> m_bufferView; + Rc<DxvkImageView> m_imageView; + Rc<DxvkBuffer> m_counterBuffer; + + Rc<DxvkBuffer> CreateCounterBuffer(); + + }; + +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/meson.build b/src/libs/dxvk-native-1.9.2a/src/d3d11/meson.build new file mode 100644 index 00000000..ded034c9 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/meson.build @@ -0,0 +1,88 @@ +d3d11_res = wrc_generator.process('version.rc') + +dxgi_common_src = [ + '../dxgi/dxgi_format.cpp', + '../dxgi/dxgi_monitor.cpp', + '../dxgi/dxgi_swapchain.cpp', +] + +d3d10_src = [ + '../d3d10/d3d10_blend.cpp', + '../d3d10/d3d10_buffer.cpp', + '../d3d10/d3d10_depth_stencil.cpp', + '../d3d10/d3d10_device.cpp', + '../d3d10/d3d10_input_layout.cpp', + '../d3d10/d3d10_multithread.cpp', + '../d3d10/d3d10_query.cpp', + '../d3d10/d3d10_rasterizer.cpp', + '../d3d10/d3d10_sampler.cpp', + '../d3d10/d3d10_texture.cpp', + '../d3d10/d3d10_util.cpp', + '../d3d10/d3d10_view_dsv.cpp', + '../d3d10/d3d10_view_rtv.cpp', + '../d3d10/d3d10_view_srv.cpp', +] + +d3d11_src = [ + 'd3d11_annotation.cpp', + 'd3d11_blend.cpp', + 'd3d11_buffer.cpp', + 'd3d11_class_linkage.cpp', + 'd3d11_cmdlist.cpp', + 'd3d11_context.cpp', + 'd3d11_context_def.cpp', + 'd3d11_context_ext.cpp', + 'd3d11_context_imm.cpp', + 'd3d11_cuda.cpp', + 'd3d11_depth_stencil.cpp', + 'd3d11_device.cpp', + 'd3d11_enums.cpp', + 'd3d11_initializer.cpp', + 'd3d11_input_layout.cpp', + 'd3d11_interop.cpp', + 'd3d11_main.cpp', + 'd3d11_options.cpp', + 'd3d11_query.cpp', + 'd3d11_rasterizer.cpp', + 'd3d11_resource.cpp', + 'd3d11_sampler.cpp', + 'd3d11_shader.cpp', + 'd3d11_state.cpp', + 'd3d11_state_object.cpp', + 'd3d11_swapchain.cpp', + 'd3d11_texture.cpp', + 'd3d11_util.cpp', + 'd3d11_video.cpp', + 'd3d11_view_dsv.cpp', + 'd3d11_view_rtv.cpp', + 'd3d11_view_srv.cpp', + 'd3d11_view_uav.cpp', +] + +d3d11_shaders = files([ + 'shaders/d3d11_video_blit_frag.frag', + 'shaders/d3d11_video_blit_vert.vert', +]) + +if not dxvk_native + # We don't want to allow GDI interop on *any* native builds + # because the idea is for you to write once and run anywhere. + d3d11_src += 'd3d11_gdi.cpp' +endif + +if dxvk_native + lib_dxgi = dxgi_dep +endif + +d3d11_dll = shared_library(so_prefix+'d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src, + glsl_generator.process(d3d11_shaders), d3d11_res, + name_prefix : '', + dependencies : [ lib_dxgi, dxbc_dep, dxvk_dep, wsi_dep ], + include_directories : dxvk_include_path, + install : true, + vs_module_defs : 'd3d11'+def_spec_ext, + override_options : ['cpp_std='+dxvk_cpp_std]) + +d3d11_dep = declare_dependency( + link_with : [ d3d11_dll ], + include_directories : [ dxvk_include_path ]) diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_frag.frag b/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_frag.frag new file mode 100644 index 00000000..d659176c --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_frag.frag @@ -0,0 +1,56 @@ +#version 450 + +layout(constant_id = 3) const bool c_planar = true; + +// Can't use matrix types here since even a two-row +// matrix will be padded to 16 bytes per column for +// absolutely no reason +layout(std140, set = 0, binding = 0) +uniform ubo_t { + vec4 color_matrix_r1; + vec4 color_matrix_r2; + vec4 color_matrix_r3; + vec2 coord_matrix_c1; + vec2 coord_matrix_c2; + vec2 coord_matrix_c3; + float y_min; + float y_max; +}; + +layout(location = 0) in vec2 i_texcoord; +layout(location = 0) out vec4 o_color; + +layout(set = 0, binding = 1) uniform sampler s_sampler; +layout(set = 0, binding = 2) uniform texture2D s_inputY; +layout(set = 0, binding = 3) uniform texture2D s_inputCbCr; + +void main() { + // Transform input texture coordinates to + // account for rotation and source rectangle + mat3x2 coord_matrix = mat3x2( + coord_matrix_c1, + coord_matrix_c2, + coord_matrix_c3); + + vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f); + + // Fetch source image color + vec4 color = vec4(0.0f, 0.0f, 0.0f, 1.0f); + + if (c_planar) { + color.g = texture(sampler2D(s_inputY, s_sampler), coord).r; + color.rb = texture(sampler2D(s_inputCbCr, s_sampler), coord).gr; + color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f); + } else { + color = texture(sampler2D(s_inputY, s_sampler), coord); + } + + // Color space transformation + mat3x4 color_matrix = mat3x4( + color_matrix_r1, + color_matrix_r2, + color_matrix_r3); + + o_color.rgb = vec4(color.rgb, 1.0f) * color_matrix; + o_color.a = color.a; +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_vert.vert b/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_vert.vert new file mode 100644 index 00000000..1980b3c9 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_vert.vert @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0) out vec2 o_texcoord; + +void main() { + vec2 coord = vec2( + float(gl_VertexIndex & 1) * 2.0f, + float(gl_VertexIndex & 2)); + + o_texcoord = coord; + gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f); +} diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/version.rc b/src/libs/dxvk-native-1.9.2a/src/d3d11/version.rc new file mode 100644 index 00000000..060ef7bc --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/version.rc @@ -0,0 +1,32 @@ +#include <windows.h> + +// DLL version information. +VS_VERSION_INFO VERSIONINFO +FILEVERSION 10,0,17763,1 +PRODUCTVERSION 10,0,17763,1 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS 0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DLL +FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "CompanyName", "DXVK" + VALUE "FileDescription", "Direct3D 11 Runtime" + VALUE "FileVersion", "10.0.17763.1 (WinBuild.160101.0800)" + VALUE "InternalName", "D3D11.dll" + VALUE "LegalCopyright", "zlib/libpng license" + VALUE "OriginalFilename", "D3D11.dll" + VALUE "ProductName", "DXVK" + VALUE "ProductVersion", "10.0.17763.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0809, 1200 + END +END + |