From d2c62a864521abc86b2b7dc01103d9fc642ee695 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 25 Jul 2018 22:45:23 +0200 Subject: [PATCH] [dxbc] Implement passthrough geometry shader This is needed when vertex or domain shader code is passed to CreateGeometryShaderWithStreamOutput. - Fix compilation with new DxbcProgramInfo. --- src/dxbc/dxbc_compiler.cpp | 62 ++++++++++++++++++++++++++++++++++++-- src/dxbc/dxbc_compiler.h | 19 +++++++++++- src/dxbc/dxbc_module.cpp | 19 ++++++++++++ src/dxbc/dxbc_module.h | 14 +++++++++ 4 files changed, 110 insertions(+), 4 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 33bdb753..9c2fc70a 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -177,6 +177,36 @@ namespace dxvk { ins.op)); } } + + + void DxbcCompiler::processXfbPassthrough() { + m_module.setExecutionMode (m_entryPointId, spv::ExecutionModeInputPoints); + m_module.setExecutionMode (m_entryPointId, spv::ExecutionModeOutputPoints); + m_module.setOutputVertices(m_entryPointId, 1); + m_module.setInvocations (m_entryPointId, 1); + + for (auto e = m_isgn->begin(); e != m_isgn->end(); e++) { + emitDclInput(e->registerId, 1, + e->componentMask, e->systemValue, + DxbcInterpolationMode::Undefined); + } + + // Figure out which streams to enable + uint32_t streamMask = 0; + + for (size_t i = 0; i < m_xfbVars.size(); i++) + streamMask |= 1u << m_xfbVars[i].streamId; + + for (uint32_t mask = streamMask; mask != 0; mask &= mask - 1) { + const uint32_t streamId = bit::tzcnt(mask); + + emitXfbOutputSetup(streamId, true); + m_module.opEmitVertex(m_module.constu32(streamId)); + } + + // End the main function + emitFunctionEnd(); + } Rc DxbcCompiler::finalize() { @@ -2078,7 +2108,7 @@ namespace dxvk { emitOutputSetup(); emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances); emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances); - emitXfbOutputSetup(streamId); + emitXfbOutputSetup(streamId, false); m_module.opEmitVertex(streamVar); } @@ -4254,6 +4284,21 @@ namespace dxvk { } + DxbcRegisterPointer DxbcCompiler::emitArrayAccess( + DxbcRegisterPointer pointer, + spv::StorageClass sclass, + uint32_t index) { + uint32_t ptrTypeId = m_module.defPointerType( + getVectorTypeId(pointer.type), sclass); + + DxbcRegisterPointer result; + result.type = pointer.type; + result.id = m_module.opAccessChain( + ptrTypeId, pointer.id, 1, &index); + return result; + } + + uint32_t DxbcCompiler::emitLoadSampledImage( const DxbcShaderResource& textureResource, const DxbcSampler& samplerResource, @@ -6292,10 +6337,21 @@ namespace dxvk { } - void DxbcCompiler::emitXfbOutputSetup(uint32_t streamId) { + void DxbcCompiler::emitXfbOutputSetup( + uint32_t streamId, + bool passthrough) { for (size_t i = 0; i < m_xfbVars.size(); i++) { if (m_xfbVars[i].streamId == streamId) { - DxbcRegisterPointer srcPtr = m_oRegs[m_xfbVars[i].outputId]; + DxbcRegisterPointer srcPtr = passthrough + ? m_vRegs[m_xfbVars[i].outputId] + : m_oRegs[m_xfbVars[i].outputId]; + + if (passthrough) { + srcPtr = emitArrayAccess(srcPtr, + spv::StorageClassInput, + m_module.constu32(0)); + } + DxbcRegisterPointer dstPtr; dstPtr.type.ctype = DxbcScalarType::Float32; dstPtr.type.ccount = m_xfbVars[i].dstMask.popCount(); diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 2e5e20fd..d1aff00f 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -382,6 +382,15 @@ namespace dxvk { void processInstruction( const DxbcShaderInstruction& ins); + /** + * \brief Emits transform feedback passthrough + * + * Writes all captured input variables to the + * corresponding xfb outputs, and sets up the + * geometry shader for point-to-point mode. + */ + void processXfbPassthrough(); + /** * \brief Finalizes the shader * \returns The final shader object @@ -851,6 +860,13 @@ namespace dxvk { DxbcRegisterValue value, DxbcOpModifiers modifiers); + //////////////////////////////// + // Pointer manipulation methods + DxbcRegisterPointer emitArrayAccess( + DxbcRegisterPointer pointer, + spv::StorageClass sclass, + uint32_t index); + /////////////////////////////////////// // Image register manipulation methods uint32_t emitLoadSampledImage( @@ -1065,7 +1081,8 @@ namespace dxvk { void emitXfbOutputDeclarations(); void emitXfbOutputSetup( - uint32_t streamId); + uint32_t streamId, + bool passthrough); /////////////////////////////// // Hull shader phase methods diff --git a/src/dxbc/dxbc_module.cpp b/src/dxbc/dxbc_module.cpp index 5463cf9a..e712438d 100644 --- a/src/dxbc/dxbc_module.cpp +++ b/src/dxbc/dxbc_module.cpp @@ -64,6 +64,25 @@ namespace dxvk { } + Rc DxbcModule::compilePassthroughShader( + const DxbcModuleInfo& moduleInfo, + const std::string& fileName) const { + if (m_shexChunk == nullptr) + throw DxvkError("DxbcModule::compile: No SHDR/SHEX chunk"); + + DxbcAnalysisInfo analysisInfo; + + DxbcCompiler compiler( + fileName, moduleInfo, + DxbcProgramType::GeometryShader, + m_osgnChunk, m_osgnChunk, + analysisInfo); + + compiler.processXfbPassthrough(); + return compiler.finalize(); + } + + void DxbcModule::runAnalyzer( DxbcAnalyzer& analyzer, DxbcCodeSlice slice) const { diff --git a/src/dxbc/dxbc_module.h b/src/dxbc/dxbc_module.h index fc420e70..35b20160 100644 --- a/src/dxbc/dxbc_module.h +++ b/src/dxbc/dxbc_module.h @@ -60,6 +60,20 @@ namespace dxvk { const DxbcModuleInfo& moduleInfo, const std::string& fileName) const; + /** + * \brief Compiles a pass-through geometry shader + * + * Applications can pass a vertex shader to create + * a geometry shader with stream output. In this + * case, we have to create a passthrough geometry + * shader, which operates in point to point mode. + * \param [in] moduleInfo DXBC module info + * \param [in] fileName SPIR-V shader name + */ + Rc compilePassthroughShader( + const DxbcModuleInfo& moduleInfo, + const std::string& fileName) const; + private: DxbcHeader m_header;