diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 231fdd72..ebbd089b 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -59,7 +59,7 @@ namespace dxvk { void D3D11DeviceContext::ClearState() { // this->IASetInputLayout(nullptr); -// this->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED); + 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); @@ -429,7 +429,77 @@ namespace dxvk { void D3D11DeviceContext::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology) { - Logger::err("D3D11DeviceContext::IASetPrimitiveTopology: Not implemented"); + if (m_state.ia.primitiveTopology != Topology) { + m_state.ia.primitiveTopology = Topology; + + Rc iaState; + + switch (Topology) { + case D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED: + break; + + case D3D11_PRIMITIVE_TOPOLOGY_POINTLIST: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + VK_FALSE); + break; + + case D3D11_PRIMITIVE_TOPOLOGY_LINELIST: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + VK_FALSE); + break; + + case D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, + VK_TRUE); + break; + + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + VK_FALSE); + break; + + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + VK_TRUE); + break; + + case D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, + VK_FALSE); + break; + + case D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, + VK_TRUE); + break; + + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, + VK_FALSE); + break; + + case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: + iaState = new DxvkInputAssemblyState( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, + VK_TRUE); + break; + + default: + Logger::err(str::format( + "D3D11DeviceContext::IASetPrimitiveTopology: Unknown primitive topology: ", + Topology)); + } + + m_context->setInputAssemblyState(iaState); + } } @@ -457,7 +527,7 @@ namespace dxvk { void D3D11DeviceContext::IAGetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY* pTopology) { - Logger::err("D3D11DeviceContext::IAGetPrimitiveTopology: Not implemented"); + *pTopology = m_state.ia.primitiveTopology; } diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index 19984660..7c4efa7d 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -553,6 +553,8 @@ namespace dxvk { void ApplyViewportState(); + void SetupIAStateObjects(); + }; } diff --git a/src/d3d11/d3d11_context_state.h b/src/d3d11/d3d11_context_state.h index ce5b0cff..c68ef1f9 100644 --- a/src/d3d11/d3d11_context_state.h +++ b/src/d3d11/d3d11_context_state.h @@ -61,7 +61,7 @@ namespace dxvk { struct D3D11ContextStateIA { - + D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; }; diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 5c1fe054..f9a4d53d 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -4,6 +4,7 @@ #include "d3d11_context.h" #include "d3d11_device.h" #include "d3d11_present.h" +#include "d3d11_shader.h" #include "d3d11_texture.h" #include "d3d11_view.h" @@ -270,8 +271,18 @@ namespace dxvk { SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11VertexShader** ppVertexShader) { - Logger::err("D3D11Device::CreateVertexShader: Not implemented"); - return E_NOTIMPL; + D3D11ShaderModule module; + + if (FAILED(this->CreateShaderModule(&module, + pShaderBytecode, BytecodeLength, pClassLinkage))) + return E_INVALIDARG; + + if (ppVertexShader != nullptr) { + *ppVertexShader = ref(new D3D11VertexShader( + this, std::move(module))); + } + + return S_OK; } @@ -305,8 +316,18 @@ namespace dxvk { SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11PixelShader** ppPixelShader) { - Logger::err("D3D11Device::CreatePixelShader: Not implemented"); - return E_NOTIMPL; + D3D11ShaderModule module; + + if (FAILED(this->CreateShaderModule(&module, + pShaderBytecode, BytecodeLength, pClassLinkage))) + return E_INVALIDARG; + + if (ppPixelShader != nullptr) { + *ppPixelShader = ref(new D3D11PixelShader( + this, std::move(module))); + } + + return S_OK; } @@ -605,4 +626,25 @@ namespace dxvk { return enabled; } + + HRESULT D3D11Device::CreateShaderModule( + D3D11ShaderModule* pShaderModule, + const void* pShaderBytecode, + size_t BytecodeLength, + ID3D11ClassLinkage* pClassLinkage) { + if (pClassLinkage != nullptr) { + Logger::err("D3D11Device::CreateShaderModule: Class linkage not supported"); + return E_INVALIDARG; + } + + try { + *pShaderModule = D3D11ShaderModule( + pShaderBytecode, BytecodeLength); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_INVALIDARG; + } + } + } diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index c179b31c..a37e9b59 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -13,6 +13,7 @@ namespace dxvk { class DxgiAdapter; class D3D11DeviceContext; class D3D11PresentDevice; + class D3D11ShaderModule; class D3D11Device : public ComObject { @@ -245,6 +246,12 @@ namespace dxvk { D3D11StateObjectSet m_rsStateObjects; + HRESULT CreateShaderModule( + D3D11ShaderModule* pShaderModule, + const void* pShaderBytecode, + size_t BytecodeLength, + ID3D11ClassLinkage* pClassLinkage); + }; } diff --git a/src/d3d11/d3d11_shader.cpp b/src/d3d11/d3d11_shader.cpp index 6694f0a8..e28a94ca 100644 --- a/src/d3d11/d3d11_shader.cpp +++ b/src/d3d11/d3d11_shader.cpp @@ -1,8 +1,83 @@ -#include "d3d11_device.h" #include "d3d11_shader.h" namespace dxvk { + static std::string GetEnvVar(LPCWSTR name) { + DWORD len = ::GetEnvironmentVariableW(name, nullptr, 0); + + std::wstring result; + + while (len > result.size()) { + result.resize(len); + len = ::GetEnvironmentVariableW( + name, result.data(), result.size()); + } + + result.resize(len); + return str::fromws(result); + } + D3D11ShaderModule:: D3D11ShaderModule() { } + D3D11ShaderModule::~D3D11ShaderModule() { } + + + D3D11ShaderModule::D3D11ShaderModule( + const void* pShaderBytecode, + size_t BytecodeLength) { + + DxbcReader reader( + reinterpret_cast(pShaderBytecode), + BytecodeLength); + + DxbcModule module(reader); + m_code = module.compile(); + + // TODO pre-process shader bindings + + // If requested by the user, dump both the raw DXBC + // shader and the compiled SPIR-V module to a file. + const std::string dumpPath = GetEnvVar(L"DXVK_SHADER_DUMP_PATH"); + + if (dumpPath.size() != 0) { + const std::string baseName = str::format(dumpPath, "/", + ConstructFileName(ComputeShaderHash(pShaderBytecode, BytecodeLength), + module.version().type())); + + reader.store(std::ofstream(str::format(baseName, ".dxbc"), + std::ios_base::binary | std::ios_base::trunc)); + + m_code.store(std::ofstream(str::format(baseName, ".spv"), + std::ios_base::binary | std::ios_base::trunc)); + } + } + + + Sha1Hash D3D11ShaderModule::ComputeShaderHash( + const void* pShaderBytecode, + size_t BytecodeLength) const { + return Sha1Hash::compute( + reinterpret_cast(pShaderBytecode), + BytecodeLength); + } + + + std::string D3D11ShaderModule::ConstructFileName( + const Sha1Hash& hash, + const DxbcProgramType& type) const { + + std::string typeStr; + + switch (type) { + case DxbcProgramType::PixelShader: typeStr = "PS_"; break; + case DxbcProgramType::VertexShader: typeStr = "VS_"; break; + case DxbcProgramType::GeometryShader: typeStr = "GS_"; break; + case DxbcProgramType::HullShader: typeStr = "HS_"; break; + case DxbcProgramType::DomainShader: typeStr = "DS_"; break; + case DxbcProgramType::ComputeShader: typeStr = "CS_"; break; + } + + return str::format(typeStr, hash.toString()); + } + } diff --git a/src/d3d11/d3d11_shader.h b/src/d3d11/d3d11_shader.h index 8ea1480a..e327b06c 100644 --- a/src/d3d11/d3d11_shader.h +++ b/src/d3d11/d3d11_shader.h @@ -1,7 +1,10 @@ #pragma once +#include #include +#include "../util/sha1/sha1_util.h" + #include "d3d11_device_child.h" #include "d3d11_interfaces.h" @@ -9,6 +12,36 @@ namespace dxvk { class D3D11Device; + /** + * \brief Shader module + * + * + */ + class D3D11ShaderModule { + + public: + + D3D11ShaderModule(); + D3D11ShaderModule( + const void* pShaderBytecode, + size_t BytecodeLength); + ~D3D11ShaderModule(); + + private: + + + SpirvCodeBuffer m_code; + + Sha1Hash ComputeShaderHash( + const void* pShaderBytecode, + size_t BytecodeLength) const; + + std::string ConstructFileName( + const Sha1Hash& hash, + const DxbcProgramType& type) const; + + }; + /** * \brief Common shader interface @@ -22,8 +55,8 @@ namespace dxvk { public: - D3D11Shader(D3D11Device* device) - : m_device(device) { } + D3D11Shader(D3D11Device* device, D3D11ShaderModule&& module) + : m_device(device), m_module(std::move(module)) { } ~D3D11Shader() { } @@ -40,9 +73,14 @@ namespace dxvk { *ppDevice = m_device.ref(); } + const D3D11ShaderModule& GetShaderModule() const { + return m_module; + } + private: - Com m_device; + Com m_device; + D3D11ShaderModule m_module; }; diff --git a/src/dxbc/dxbc_module.h b/src/dxbc/dxbc_module.h index 3d5be120..b1291e7e 100644 --- a/src/dxbc/dxbc_module.h +++ b/src/dxbc/dxbc_module.h @@ -27,6 +27,14 @@ namespace dxvk { DxbcModule(DxbcReader& reader); ~DxbcModule(); + /** + * \brief Shader type and version + * \returns Shader type and version + */ + DxbcProgramVersion version() const { + return m_shexChunk->version(); + } + /** * \brief Compiles DXBC shader to SPIR-V module * \returns The compiled DXVK shader object diff --git a/src/dxbc/dxbc_reader.cpp b/src/dxbc/dxbc_reader.cpp index b6fca61d..9b9a340a 100644 --- a/src/dxbc/dxbc_reader.cpp +++ b/src/dxbc/dxbc_reader.cpp @@ -50,4 +50,9 @@ namespace dxvk { return DxbcReader(m_data, size, m_pos); } + + void DxbcReader::store(std::ostream&& stream) const { + stream.write(m_data, m_size); + } + } \ No newline at end of file diff --git a/src/dxbc/dxbc_reader.h b/src/dxbc/dxbc_reader.h index 46d08972..a1600017 100644 --- a/src/dxbc/dxbc_reader.h +++ b/src/dxbc/dxbc_reader.h @@ -55,6 +55,8 @@ namespace dxvk { return m_pos >= m_size; } + void store(std::ostream&& stream) const; + private: DxbcReader(const char* data, size_t size, size_t pos)