From 01cc49555aac01607b31e71f9a3fa5b45460b043 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 27 Aug 2018 12:47:52 +0200 Subject: [PATCH] [dxbc] End functions correctly even if last instruction is not 'ret' Some DXBC shaders don't end in a return instruction, but rather implicitly end when all branches end in a return instruction. Fixes an illegal shader generated in Crysis 1. --- src/dxbc/dxbc_compiler.cpp | 126 +++++++++++++++++++++---------------- src/dxbc/dxbc_compiler.h | 16 ++++- 2 files changed, 86 insertions(+), 56 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 557c409c..924acead 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -3732,10 +3732,10 @@ namespace dxvk { void DxbcCompiler::emitControlFlowRet(const DxbcShaderInstruction& ins) { - m_module.opReturn(); - if (m_controlFlowBlocks.size() != 0) { uint32_t labelId = m_module.allocateId(); + + m_module.opReturn(); m_module.opLabel(labelId); // return can be used in place of break to terminate a case block @@ -3743,7 +3743,7 @@ namespace dxvk { m_controlFlowBlocks.back().b_switch.labelCase = labelId; } else { // Last instruction in the current function - m_module.functionEnd(); + this->emitFunctionEnd(); } } @@ -3767,7 +3767,6 @@ namespace dxvk { zeroTest.id, returnLabel, continueLabel); m_module.opLabel(returnLabel); - m_module.opReturn(); m_module.opLabel(continueLabel); @@ -5783,20 +5782,42 @@ namespace dxvk { } - void DxbcCompiler::emitMainFunctionBegin() { + void DxbcCompiler::emitFunctionBegin( + uint32_t entryPoint, + uint32_t returnType, + uint32_t funcType) { + this->emitFunctionEnd(); + m_module.functionBegin( - m_module.defVoidType(), - m_entryPointId, - m_module.defFunctionType( - m_module.defVoidType(), 0, nullptr), + returnType, entryPoint, funcType, spv::FunctionControlMaskNone); + + m_insideFunction = true; + } + + + void DxbcCompiler::emitFunctionEnd() { + if (m_insideFunction) { + m_module.opReturn(); + m_module.functionEnd(); + } + + m_insideFunction = false; + } + + + void DxbcCompiler::emitFunctionLabel() { m_module.opLabel(m_module.allocateId()); } - void DxbcCompiler::emitMainFunctionEnd() { - m_module.opReturn(); - m_module.functionEnd(); + void DxbcCompiler::emitMainFunctionBegin() { + this->emitFunctionBegin( + m_entryPointId, + m_module.defVoidType(), + m_module.defFunctionType( + m_module.defVoidType(), 0, nullptr)); + this->emitFunctionLabel(); } @@ -5836,13 +5857,12 @@ namespace dxvk { m_vs.functionId = m_module.allocateId(); m_module.setDebugName(m_vs.functionId, "vs_main"); - m_module.functionBegin( - m_module.defVoidType(), + this->emitFunctionBegin( m_vs.functionId, + m_module.defVoidType(), m_module.defFunctionType( - m_module.defVoidType(), 0, nullptr), - spv::FunctionControlMaskNone); - m_module.opLabel(m_module.allocateId()); + m_module.defVoidType(), 0, nullptr)); + this->emitFunctionLabel(); } @@ -5896,13 +5916,12 @@ namespace dxvk { m_ds.functionId = m_module.allocateId(); m_module.setDebugName(m_ds.functionId, "ds_main"); - m_module.functionBegin( - m_module.defVoidType(), + this->emitFunctionBegin( m_ds.functionId, + m_module.defVoidType(), m_module.defFunctionType( - m_module.defVoidType(), 0, nullptr), - spv::FunctionControlMaskNone); - m_module.opLabel(m_module.allocateId()); + m_module.defVoidType(), 0, nullptr)); + this->emitFunctionLabel(); } @@ -5938,13 +5957,12 @@ namespace dxvk { m_gs.functionId = m_module.allocateId(); m_module.setDebugName(m_gs.functionId, "gs_main"); - m_module.functionBegin( - m_module.defVoidType(), + this->emitFunctionBegin( m_gs.functionId, + m_module.defVoidType(), m_module.defFunctionType( - m_module.defVoidType(), 0, nullptr), - spv::FunctionControlMaskNone); - m_module.opLabel(m_module.allocateId()); + m_module.defVoidType(), 0, nullptr)); + this->emitFunctionLabel(); } @@ -5983,13 +6001,12 @@ namespace dxvk { m_ps.functionId = m_module.allocateId(); m_module.setDebugName(m_ps.functionId, "ps_main"); - m_module.functionBegin( - m_module.defVoidType(), + this->emitFunctionBegin( m_ps.functionId, + m_module.defVoidType(), m_module.defFunctionType( - m_module.defVoidType(), 0, nullptr), - spv::FunctionControlMaskNone); - m_module.opLabel(m_module.allocateId()); + m_module.defVoidType(), 0, nullptr)); + this->emitFunctionLabel(); } @@ -5998,13 +6015,12 @@ namespace dxvk { m_cs.functionId = m_module.allocateId(); m_module.setDebugName(m_cs.functionId, "cs_main"); - m_module.functionBegin( - m_module.defVoidType(), + this->emitFunctionBegin( m_cs.functionId, + m_module.defVoidType(), m_module.defFunctionType( - m_module.defVoidType(), 0, nullptr), - spv::FunctionControlMaskNone); - m_module.opLabel(m_module.allocateId()); + m_module.defVoidType(), 0, nullptr)); + this->emitFunctionLabel(); } @@ -6017,7 +6033,7 @@ namespace dxvk { this->emitOutputSetup(); this->emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances); this->emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances); - this->emitMainFunctionEnd(); + this->emitFunctionEnd(); } @@ -6042,7 +6058,7 @@ namespace dxvk { this->emitOutputSetup(); this->emitHsInvocationBlockEnd(); - this->emitMainFunctionEnd(); + this->emitFunctionEnd(); } @@ -6054,7 +6070,7 @@ namespace dxvk { this->emitOutputSetup(); this->emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances); this->emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances); - this->emitMainFunctionEnd(); + this->emitFunctionEnd(); } @@ -6067,7 +6083,7 @@ namespace dxvk { m_gs.functionId, 0, nullptr); // No output setup at this point as that was // already done during the EmitVertex step - this->emitMainFunctionEnd(); + this->emitFunctionEnd(); } @@ -6098,7 +6114,7 @@ namespace dxvk { } this->emitOutputSetup(); - this->emitMainFunctionEnd(); + this->emitFunctionEnd(); } @@ -6107,7 +6123,7 @@ namespace dxvk { m_module.opFunctionCall( m_module.defVoidType(), m_cs.functionId, 0, nullptr); - this->emitMainFunctionEnd(); + this->emitFunctionEnd(); } @@ -6212,9 +6228,10 @@ namespace dxvk { uint32_t funId = m_module.allocateId(); - m_module.functionBegin(m_module.defVoidType(), - funId, funTypeId, spv::FunctionControlMaskNone); - m_module.opLabel(m_module.allocateId()); + this->emitFunctionBegin(funId, + m_module.defVoidType(), + funTypeId); + this->emitFunctionLabel(); DxbcCompilerHsControlPointPhase result; result.functionId = funId; @@ -6230,9 +6247,10 @@ namespace dxvk { uint32_t funId = m_module.allocateId(); m_module.setDebugName(funId, "hs_passthrough"); - m_module.functionBegin(m_module.defVoidType(), - funId, funTypeId, spv::FunctionControlMaskNone); - m_module.opLabel(m_module.allocateId()); + this->emitFunctionBegin(funId, + m_module.defVoidType(), + funTypeId); + this->emitFunctionLabel(); // We'll basically copy each input variable to the corresponding // output, using the shader's invocation ID as the array index. @@ -6270,8 +6288,7 @@ namespace dxvk { } // End function - m_module.opReturn(); - m_module.functionEnd(); + this->emitFunctionEnd(); DxbcCompilerHsControlPointPhase result; result.functionId = funId; @@ -6286,11 +6303,12 @@ namespace dxvk { uint32_t funId = m_module.allocateId(); - m_module.functionBegin(m_module.defVoidType(), - funId, funTypeId, spv::FunctionControlMaskNone); + this->emitFunctionBegin(funId, + m_module.defVoidType(), + funTypeId); uint32_t argId = m_module.functionParameter(argTypeId); - m_module.opLabel(m_module.allocateId()); + this->emitFunctionLabel(); DxbcCompilerHsForkJoinPhase result; result.functionId = funId; diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 1ef84a08..dfac4a41 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -431,6 +431,11 @@ namespace dxvk { // currently active if-else blocks and loops. std::vector m_controlFlowBlocks; + ////////////////////////////////////////////// + // Function state tracking. Required in order + // to properly end functions in some cases. + bool m_insideFunction = false; + /////////////////////////////////////////////// // Specialization constants. These are defined // as needed by the getSpecConstant method. @@ -1008,9 +1013,16 @@ namespace dxvk { // Common function definition methods void emitInit(); - void emitMainFunctionBegin(); + void emitFunctionBegin( + uint32_t entryPoint, + uint32_t returnType, + uint32_t funcType); - void emitMainFunctionEnd(); + void emitFunctionEnd(); + + void emitFunctionLabel(); + + void emitMainFunctionBegin(); ///////////////////////////////// // Shader initialization methods