From 6a5fe2247ad351c50a4d7dc7d5ea421ba1168822 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 23 Jun 2018 23:46:24 +0200 Subject: [PATCH] [dxbc] Add support for multiple streams in geometry shaders --- src/dxbc/dxbc_compiler.cpp | 24 +++++++++++++++++++++--- src/spirv/spirv_module.cpp | 20 ++++++++++++++++---- src/spirv/spirv_module.h | 6 ++++-- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index f3f36d03d..7e5c80dcb 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -796,7 +796,7 @@ namespace dxvk { void DxbcCompiler::emitDclStream(const DxbcShaderInstruction& ins) { - if (ins.dst[0].idx[0].offset != 0) + if (ins.dst[0].idx[0].offset != 0 && m_moduleInfo.xfb == nullptr) Logger::err("Dxbc: Multiple streams not supported"); } @@ -2053,6 +2053,16 @@ namespace dxvk { void DxbcCompiler::emitGeometryEmit(const DxbcShaderInstruction& ins) { + // In xfb mode we might have multiple streams, so + // we have to figure out which stream to write to + uint32_t streamId = 0; + uint32_t streamVar = 0; + + if (m_moduleInfo.xfb != nullptr) { + streamId = ins.dstCount > 0 ? ins.dst[0].idx[0].offset : 0; + streamVar = m_module.constu32(streamId); + } + // Checking the negation is easier for EmitThenCut/EmitThenCutStream bool doEmit = ins.op != DxbcOpcode::Cut && ins.op != DxbcOpcode::CutStream; bool doCut = ins.op != DxbcOpcode::Emit && ins.op != DxbcOpcode::EmitStream; @@ -2061,11 +2071,11 @@ namespace dxvk { emitOutputSetup(); emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances); emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances); - m_module.opEmitVertex(); + m_module.opEmitVertex(streamVar); } if (doCut) - m_module.opEndPrimitive(); + m_module.opEndPrimitive(streamVar); } @@ -6008,6 +6018,14 @@ namespace dxvk { m_module.enableCapability(spv::CapabilityGeometry); m_module.enableCapability(spv::CapabilityClipDistance); m_module.enableCapability(spv::CapabilityCullDistance); + + // Enable capabilities for xfb mode if necessary + if (m_moduleInfo.xfb != nullptr) { + m_module.enableCapability(spv::CapabilityGeometryStreams); + m_module.enableCapability(spv::CapabilityTransformFeedback); + + m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeXfb); + } // Declare the per-vertex output block. Outputs are not // declared as arrays, instead they will be flushed when diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index 771ba027e..bd69bde81 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -2937,13 +2937,25 @@ namespace dxvk { } - void SpirvModule::opEmitVertex() { - m_code.putIns (spv::OpEmitVertex, 1); + void SpirvModule::opEmitVertex( + uint32_t streamId) { + if (streamId == 0) { + m_code.putIns (spv::OpEmitVertex, 1); + } else { + m_code.putIns (spv::OpEmitStreamVertex, 2); + m_code.putWord(streamId); + } } - void SpirvModule::opEndPrimitive() { - m_code.putIns (spv::OpEndPrimitive, 1); + void SpirvModule::opEndPrimitive( + uint32_t streamId) { + if (streamId == 0) { + m_code.putIns (spv::OpEndPrimitive, 1); + } else { + m_code.putIns (spv::OpEndStreamPrimitive, 2); + m_code.putWord(streamId); + } } diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index 73b702e0b..9886fd3ec 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -1022,9 +1022,11 @@ namespace dxvk { void opKill(); - void opEmitVertex(); + void opEmitVertex( + uint32_t streamId); - void opEndPrimitive(); + void opEndPrimitive( + uint32_t streamId); private: