From 1f89452014fc7a84769b33f2ac3861f2f3985414 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 7 Dec 2017 12:45:02 +0100 Subject: [PATCH] [d3d11] Implemented input layout creation --- src/d3d11/d3d11_context.cpp | 16 ++++-- src/d3d11/d3d11_context_state.h | 2 + src/d3d11/d3d11_device.cpp | 95 +++++++++++++++++++++++++++++++- src/d3d11/d3d11_input_layout.cpp | 33 +++++++++++ src/d3d11/d3d11_input_layout.h | 37 +++++++++++++ src/d3d11/meson.build | 1 + src/dxbc/dxbc_chunk_isgn.cpp | 13 +++++ src/dxbc/dxbc_chunk_isgn.h | 4 ++ src/dxbc/dxbc_module.h | 9 +++ 9 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 src/d3d11/d3d11_input_layout.cpp create mode 100644 src/d3d11/d3d11_input_layout.h diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 74cd3d576..4ea4500aa 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -58,7 +58,7 @@ namespace dxvk { void D3D11DeviceContext::ClearState() { -// this->IASetInputLayout(nullptr); + this->IASetInputLayout(nullptr); this->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED); // this->IASetVertexBuffers(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT, nullptr, nullptr, nullptr); // this->IASetIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0); @@ -424,7 +424,15 @@ namespace dxvk { void D3D11DeviceContext::IASetInputLayout(ID3D11InputLayout* pInputLayout) { - Logger::err("D3D11DeviceContext::IASetInputLayout: Not implemented"); + auto inputLayout = static_cast(pInputLayout); + + if (m_state.ia.inputLayout != inputLayout) { + m_state.ia.inputLayout = inputLayout; + + m_context->setInputLayout(inputLayout != nullptr + ? inputLayout->GetDXVKInputLayout() + : nullptr); + } } @@ -522,7 +530,7 @@ namespace dxvk { void D3D11DeviceContext::IAGetInputLayout(ID3D11InputLayout** ppInputLayout) { - Logger::err("D3D11DeviceContext::IAGetInputLayout: Not implemented"); + *ppInputLayout = m_state.ia.inputLayout.ref(); } @@ -822,7 +830,7 @@ namespace dxvk { auto shader = static_cast(pPixelShader); if (NumClassInstances != 0) - Logger::err("D3D11DeviceContext::VSSetShader: Class instances not supported"); + Logger::err("D3D11DeviceContext::PSSetShader: Class instances not supported"); if (m_state.ps.shader != shader) { m_state.ps.shader = shader; diff --git a/src/d3d11/d3d11_context_state.h b/src/d3d11/d3d11_context_state.h index c68ef1f93..df2b20c43 100644 --- a/src/d3d11/d3d11_context_state.h +++ b/src/d3d11/d3d11_context_state.h @@ -3,6 +3,7 @@ #include #include "d3d11_buffer.h" +#include "d3d11_input_layout.h" #include "d3d11_shader.h" #include "d3d11_state.h" #include "d3d11_view.h" @@ -61,6 +62,7 @@ namespace dxvk { struct D3D11ContextStateIA { + Com inputLayout; D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; }; diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 779438a90..68842cd30 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -3,6 +3,7 @@ #include "d3d11_buffer.h" #include "d3d11_context.h" #include "d3d11_device.h" +#include "d3d11_input_layout.h" #include "d3d11_present.h" #include "d3d11_shader.h" #include "d3d11_texture.h" @@ -261,8 +262,98 @@ namespace dxvk { const void* pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength, ID3D11InputLayout** ppInputLayout) { - Logger::err("D3D11Device::CreateInputLayout: Not implemented"); - return E_NOTIMPL; + try { + DxbcReader dxbcReader(reinterpret_cast( + pShaderBytecodeWithInputSignature), BytecodeLength); + DxbcModule dxbcModule(dxbcReader); + + Rc inputSignature = dxbcModule.isgn(); + + std::vector attributes; + std::vector bindings; + + for (uint32_t i = 0; i < NumElements; i++) { + const DxbcSgnEntry* entry = inputSignature->find( + pInputElementDescs[i].SemanticName, + pInputElementDescs[i].SemanticIndex); + + if (entry == nullptr) { + Logger::err(str::format( + "D3D11Device::CreateInputLayout: No such semantic: ", + pInputElementDescs[i].SemanticName, + pInputElementDescs[i].SemanticIndex)); + return E_INVALIDARG; + } + + // Create vertex input attribute description + VkVertexInputAttributeDescription attrib; + attrib.location = entry->registerId; + attrib.binding = pInputElementDescs[i].InputSlot; + attrib.format = m_dxgiAdapter->LookupFormat( + pInputElementDescs[i].Format).actual; + attrib.offset = pInputElementDescs[i].AlignedByteOffset; + + if (attrib.offset == D3D11_APPEND_ALIGNED_ELEMENT) { + Logger::err("D3D11Device::CreateInputLayout: D3D11_APPEND_ALIGNED_ELEMENT not supported yet"); + return E_INVALIDARG; + } + + attributes.push_back(attrib); + + // Create vertex input binding description. + VkVertexInputBindingDescription binding; + binding.binding = pInputElementDescs[i].InputSlot; + binding.stride = 0; + binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + if (pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA) { + binding.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; + + if (pInputElementDescs[i].InstanceDataStepRate != 1) { + Logger::err(str::format( + "D3D11Device::CreateInputLayout: Unsupported instance data step rate: ", + pInputElementDescs[i].InstanceDataStepRate)); + } + } + + // Check if the binding was already defined. If so, the + // parameters must be identical (namely, the input rate). + bool bindingDefined = false; + + for (const auto& existingBinding : bindings) { + if (binding.binding == existingBinding.binding) { + bindingDefined = true; + + if (binding.inputRate != existingBinding.inputRate) { + Logger::err(str::format( + "D3D11Device::CreateInputLayout: Conflicting input rate for binding ", + binding.binding)); + return E_INVALIDARG; + } + } + } + + if (!bindingDefined) + bindings.push_back(binding); + } + + // Create the actual input layout object + // if the application requests it. + if (ppInputLayout != nullptr) { + *ppInputLayout = ref( + new D3D11InputLayout(this, + new DxvkInputLayout( + attributes.size(), + attributes.data(), + bindings.size(), + bindings.data()))); + } + + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } } diff --git a/src/d3d11/d3d11_input_layout.cpp b/src/d3d11/d3d11_input_layout.cpp new file mode 100644 index 000000000..eb6623c4e --- /dev/null +++ b/src/d3d11/d3d11_input_layout.cpp @@ -0,0 +1,33 @@ +#include "d3d11_device.h" +#include "d3d11_input_layout.h" + +namespace dxvk { + + D3D11InputLayout::D3D11InputLayout( + D3D11Device* pDevice, + const Rc& inputLayout) + : m_device(pDevice), m_inputLayout(inputLayout) { + + } + + + D3D11InputLayout::~D3D11InputLayout() { + + } + + + HRESULT D3D11InputLayout::QueryInterface(REFIID riid, void** ppvObject) { + COM_QUERY_IFACE(riid, ppvObject, IUnknown); + COM_QUERY_IFACE(riid, ppvObject, ID3D11DeviceChild); + COM_QUERY_IFACE(riid, ppvObject, ID3D11InputLayout); + + Logger::warn("D3D11InputLayout::QueryInterface: Unknown interface query"); + return E_NOINTERFACE; + } + + + void D3D11InputLayout::GetDevice(ID3D11Device** ppDevice) { + *ppDevice = ref(m_device); + } + +} diff --git a/src/d3d11/d3d11_input_layout.h b/src/d3d11/d3d11_input_layout.h new file mode 100644 index 000000000..3748b593d --- /dev/null +++ b/src/d3d11/d3d11_input_layout.h @@ -0,0 +1,37 @@ +#pragma once + +#include "d3d11_device_child.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11InputLayout : public D3D11DeviceChild { + + public: + + D3D11InputLayout( + D3D11Device* pDevice, + const Rc& inputLayout); + + ~D3D11InputLayout(); + + HRESULT QueryInterface( + REFIID riid, + void** ppvObject) final; + + void GetDevice( + ID3D11Device **ppDevice) final; + + Rc GetDXVKInputLayout() const { + return m_inputLayout; + } + + private: + + D3D11Device* const m_device; + Rc m_inputLayout; + + }; + +} diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index be3bb5d9f..412737284 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -3,6 +3,7 @@ d3d11_src = [ 'd3d11_context.cpp', 'd3d11_device.cpp', 'd3d11_enums.cpp', + 'd3d11_input_layout.cpp', 'd3d11_main.cpp', 'd3d11_present.cpp', 'd3d11_shader.cpp', diff --git a/src/dxbc/dxbc_chunk_isgn.cpp b/src/dxbc/dxbc_chunk_isgn.cpp index e0d1f5b0b..8b26099d3 100644 --- a/src/dxbc/dxbc_chunk_isgn.cpp +++ b/src/dxbc/dxbc_chunk_isgn.cpp @@ -29,4 +29,17 @@ namespace dxvk { } + + const DxbcSgnEntry* DxbcIsgn::find( + const std::string& semanticName, + uint32_t semanticIndex) const { + for (auto e = this->begin(); e != this->end(); e++) { + if (e->semanticName == semanticName + && e->semanticIndex == semanticIndex) + return &(*e); + } + + return nullptr; + } + } \ No newline at end of file diff --git a/src/dxbc/dxbc_chunk_isgn.h b/src/dxbc/dxbc_chunk_isgn.h index 349dd0eef..a65208f3e 100644 --- a/src/dxbc/dxbc_chunk_isgn.h +++ b/src/dxbc/dxbc_chunk_isgn.h @@ -39,6 +39,10 @@ namespace dxvk { auto begin() const { return m_entries.cbegin(); } auto end () const { return m_entries.cend(); } + const DxbcSgnEntry* find( + const std::string& semanticName, + uint32_t semanticIndex) const; + private: std::vector m_entries; diff --git a/src/dxbc/dxbc_module.h b/src/dxbc/dxbc_module.h index b1291e7e4..bada3f81e 100644 --- a/src/dxbc/dxbc_module.h +++ b/src/dxbc/dxbc_module.h @@ -35,6 +35,15 @@ namespace dxvk { return m_shexChunk->version(); } + /** + * \brief Input and output signature chunks + * + * Parts of the D3D11 API need access to the + * input or output signature of the shader. + */ + Rc isgn() const { return m_isgnChunk; } + Rc osgn() const { return m_osgnChunk; } + /** * \brief Compiles DXBC shader to SPIR-V module * \returns The compiled DXVK shader object