From 94ce76da6b392bc6ad1bcc3b16df46c531bf2ff3 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 22 Sep 2019 22:06:42 +0200 Subject: [PATCH] [dxbc] Implement label, call and callc instructions Fixes #1200. --- src/dxbc/dxbc_compiler.cpp | 80 +++++++++++++++++++++++++++++++++++++- src/dxbc/dxbc_compiler.h | 18 ++++++++- src/dxbc/dxbc_defs.cpp | 4 +- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 911f25271..c31340006 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -4174,6 +4174,63 @@ namespace dxvk { } + void DxbcCompiler::emitControlFlowLabel(const DxbcShaderInstruction& ins) { + uint32_t functionNr = ins.dst[0].idx[0].offset; + uint32_t functionId = getFunctionId(functionNr); + + this->emitFunctionBegin( + functionId, + m_module.defVoidType(), + m_module.defFunctionType( + m_module.defVoidType(), 0, nullptr)); + + m_module.opLabel(m_module.allocateId()); + m_module.setDebugName(functionId, str::format("label", functionNr).c_str()); + + m_insideFunction = true; + } + + + void DxbcCompiler::emitControlFlowCall(const DxbcShaderInstruction& ins) { + uint32_t functionNr = ins.src[0].idx[0].offset; + uint32_t functionId = getFunctionId(functionNr); + + m_module.opFunctionCall( + m_module.defVoidType(), + functionId, 0, nullptr); + } + + + void DxbcCompiler::emitControlFlowCallc(const DxbcShaderInstruction& ins) { + uint32_t functionNr = ins.src[1].idx[0].offset; + uint32_t functionId = getFunctionId(functionNr); + + // Perform zero test on the first component of the condition + const DxbcRegisterValue condition = emitRegisterLoad( + ins.src[0], DxbcRegMask(true, false, false, false)); + + const DxbcRegisterValue zeroTest = emitRegisterZeroTest( + condition, ins.controls.zeroTest()); + + // We basically have to wrap this into an 'if' block + const uint32_t callLabel = m_module.allocateId(); + const uint32_t continueLabel = m_module.allocateId(); + + m_module.opSelectionMerge(continueLabel, + spv::SelectionControlMaskNone); + + m_module.opBranchConditional( + zeroTest.id, callLabel, continueLabel); + + m_module.opLabel(callLabel); + m_module.opFunctionCall( + m_module.defVoidType(), + functionId, 0, nullptr); + + m_module.opLabel(continueLabel); + } + + void DxbcCompiler::emitControlFlow(const DxbcShaderInstruction& ins) { switch (ins.op) { case DxbcOpcode::If: @@ -4210,7 +4267,7 @@ namespace dxvk { case DxbcOpcode::Breakc: case DxbcOpcode::Continuec: return this->emitControlFlowBreakc(ins); - + case DxbcOpcode::Ret: return this->emitControlFlowRet(ins); @@ -4220,6 +4277,15 @@ namespace dxvk { case DxbcOpcode::Discard: return this->emitControlFlowDiscard(ins); + case DxbcOpcode::Label: + return this->emitControlFlowLabel(ins); + + case DxbcOpcode::Call: + return this->emitControlFlowCall(ins); + + case DxbcOpcode::Callc: + return this->emitControlFlowCallc(ins); + default: Logger::warn(str::format( "DxbcCompiler: Unhandled instruction: ", @@ -7659,6 +7725,18 @@ namespace dxvk { } + uint32_t DxbcCompiler::getFunctionId( + uint32_t functionNr) { + auto entry = m_subroutines.find(functionNr); + if (entry != m_subroutines.end()) + return entry->second; + + uint32_t functionId = m_module.allocateId(); + m_subroutines.insert({ functionNr, functionId }); + return functionId; + } + + DxbcCompilerHsForkJoinPhase* DxbcCompiler::getCurrentHsForkJoinPhase() { switch (m_hs.currPhaseType) { case DxbcCompilerHsPhase::Fork: return &m_hs.forkPhases.at(m_hs.currPhaseId); diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 39e9743f0..07df1bffe 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -472,7 +472,7 @@ namespace dxvk { // Function state tracking. Required in order // to properly end functions in some cases. bool m_insideFunction = false; - + /////////////////////////////////////////////////////////// // Array of input values. Since v# registers are indexable // in DXBC, we need to copy them into an array first. @@ -506,6 +506,10 @@ namespace dxvk { uint32_t m_uavCtrStructType = 0; uint32_t m_uavCtrPointerType = 0; + //////////////////////////////// + // Function IDs for subroutines + std::unordered_map m_subroutines; + /////////////////////////////////////////////////// // Entry point description - we'll need to declare // the function ID and all input/output variables. @@ -784,6 +788,15 @@ namespace dxvk { void emitControlFlowDiscard( const DxbcShaderInstruction& ins); + void emitControlFlowLabel( + const DxbcShaderInstruction& ins); + + void emitControlFlowCall( + const DxbcShaderInstruction& ins); + + void emitControlFlowCallc( + const DxbcShaderInstruction& ins); + void emitControlFlow( const DxbcShaderInstruction& ins); @@ -1218,6 +1231,9 @@ namespace dxvk { const DxbcRegisterInfo& type); uint32_t getPerVertexBlockId(); + + uint32_t getFunctionId( + uint32_t functionNr); DxbcCompilerHsForkJoinPhase* getCurrentHsForkJoinPhase(); diff --git a/src/dxbc/dxbc_defs.cpp b/src/dxbc/dxbc_defs.cpp index 72c40e9f2..4e383d8a6 100644 --- a/src/dxbc/dxbc_defs.cpp +++ b/src/dxbc/dxbc_defs.cpp @@ -209,7 +209,9 @@ namespace dxvk { { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 }, } }, /* Label */ - { }, + { 1, DxbcInstClass::ControlFlow, { + { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 }, + } }, /* Ld */ { 3, DxbcInstClass::TextureFetch, { { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },