1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00

[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.
This commit is contained in:
Philip Rebohle 2018-08-27 12:47:52 +02:00
parent 674aefcd17
commit 01cc49555a
2 changed files with 86 additions and 56 deletions

View File

@ -3732,10 +3732,10 @@ namespace dxvk {
void DxbcCompiler::emitControlFlowRet(const DxbcShaderInstruction& ins) { void DxbcCompiler::emitControlFlowRet(const DxbcShaderInstruction& ins) {
m_module.opReturn();
if (m_controlFlowBlocks.size() != 0) { if (m_controlFlowBlocks.size() != 0) {
uint32_t labelId = m_module.allocateId(); uint32_t labelId = m_module.allocateId();
m_module.opReturn();
m_module.opLabel(labelId); m_module.opLabel(labelId);
// return can be used in place of break to terminate a case block // 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; m_controlFlowBlocks.back().b_switch.labelCase = labelId;
} else { } else {
// Last instruction in the current function // Last instruction in the current function
m_module.functionEnd(); this->emitFunctionEnd();
} }
} }
@ -3767,7 +3767,6 @@ namespace dxvk {
zeroTest.id, returnLabel, continueLabel); zeroTest.id, returnLabel, continueLabel);
m_module.opLabel(returnLabel); m_module.opLabel(returnLabel);
m_module.opReturn(); m_module.opReturn();
m_module.opLabel(continueLabel); 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.functionBegin(
m_module.defVoidType(), returnType, entryPoint, funcType,
m_entryPointId,
m_module.defFunctionType(
m_module.defVoidType(), 0, nullptr),
spv::FunctionControlMaskNone); 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()); m_module.opLabel(m_module.allocateId());
} }
void DxbcCompiler::emitMainFunctionEnd() { void DxbcCompiler::emitMainFunctionBegin() {
m_module.opReturn(); this->emitFunctionBegin(
m_module.functionEnd(); 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_vs.functionId = m_module.allocateId();
m_module.setDebugName(m_vs.functionId, "vs_main"); m_module.setDebugName(m_vs.functionId, "vs_main");
m_module.functionBegin( this->emitFunctionBegin(
m_module.defVoidType(),
m_vs.functionId, m_vs.functionId,
m_module.defVoidType(),
m_module.defFunctionType( m_module.defFunctionType(
m_module.defVoidType(), 0, nullptr), m_module.defVoidType(), 0, nullptr));
spv::FunctionControlMaskNone); this->emitFunctionLabel();
m_module.opLabel(m_module.allocateId());
} }
@ -5896,13 +5916,12 @@ namespace dxvk {
m_ds.functionId = m_module.allocateId(); m_ds.functionId = m_module.allocateId();
m_module.setDebugName(m_ds.functionId, "ds_main"); m_module.setDebugName(m_ds.functionId, "ds_main");
m_module.functionBegin( this->emitFunctionBegin(
m_module.defVoidType(),
m_ds.functionId, m_ds.functionId,
m_module.defVoidType(),
m_module.defFunctionType( m_module.defFunctionType(
m_module.defVoidType(), 0, nullptr), m_module.defVoidType(), 0, nullptr));
spv::FunctionControlMaskNone); this->emitFunctionLabel();
m_module.opLabel(m_module.allocateId());
} }
@ -5938,13 +5957,12 @@ namespace dxvk {
m_gs.functionId = m_module.allocateId(); m_gs.functionId = m_module.allocateId();
m_module.setDebugName(m_gs.functionId, "gs_main"); m_module.setDebugName(m_gs.functionId, "gs_main");
m_module.functionBegin( this->emitFunctionBegin(
m_module.defVoidType(),
m_gs.functionId, m_gs.functionId,
m_module.defVoidType(),
m_module.defFunctionType( m_module.defFunctionType(
m_module.defVoidType(), 0, nullptr), m_module.defVoidType(), 0, nullptr));
spv::FunctionControlMaskNone); this->emitFunctionLabel();
m_module.opLabel(m_module.allocateId());
} }
@ -5983,13 +6001,12 @@ namespace dxvk {
m_ps.functionId = m_module.allocateId(); m_ps.functionId = m_module.allocateId();
m_module.setDebugName(m_ps.functionId, "ps_main"); m_module.setDebugName(m_ps.functionId, "ps_main");
m_module.functionBegin( this->emitFunctionBegin(
m_module.defVoidType(),
m_ps.functionId, m_ps.functionId,
m_module.defVoidType(),
m_module.defFunctionType( m_module.defFunctionType(
m_module.defVoidType(), 0, nullptr), m_module.defVoidType(), 0, nullptr));
spv::FunctionControlMaskNone); this->emitFunctionLabel();
m_module.opLabel(m_module.allocateId());
} }
@ -5998,13 +6015,12 @@ namespace dxvk {
m_cs.functionId = m_module.allocateId(); m_cs.functionId = m_module.allocateId();
m_module.setDebugName(m_cs.functionId, "cs_main"); m_module.setDebugName(m_cs.functionId, "cs_main");
m_module.functionBegin( this->emitFunctionBegin(
m_module.defVoidType(),
m_cs.functionId, m_cs.functionId,
m_module.defVoidType(),
m_module.defFunctionType( m_module.defFunctionType(
m_module.defVoidType(), 0, nullptr), m_module.defVoidType(), 0, nullptr));
spv::FunctionControlMaskNone); this->emitFunctionLabel();
m_module.opLabel(m_module.allocateId());
} }
@ -6017,7 +6033,7 @@ namespace dxvk {
this->emitOutputSetup(); this->emitOutputSetup();
this->emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances); this->emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances);
this->emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances); this->emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances);
this->emitMainFunctionEnd(); this->emitFunctionEnd();
} }
@ -6042,7 +6058,7 @@ namespace dxvk {
this->emitOutputSetup(); this->emitOutputSetup();
this->emitHsInvocationBlockEnd(); this->emitHsInvocationBlockEnd();
this->emitMainFunctionEnd(); this->emitFunctionEnd();
} }
@ -6054,7 +6070,7 @@ namespace dxvk {
this->emitOutputSetup(); this->emitOutputSetup();
this->emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances); this->emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances);
this->emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances); this->emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances);
this->emitMainFunctionEnd(); this->emitFunctionEnd();
} }
@ -6067,7 +6083,7 @@ namespace dxvk {
m_gs.functionId, 0, nullptr); m_gs.functionId, 0, nullptr);
// No output setup at this point as that was // No output setup at this point as that was
// already done during the EmitVertex step // already done during the EmitVertex step
this->emitMainFunctionEnd(); this->emitFunctionEnd();
} }
@ -6098,7 +6114,7 @@ namespace dxvk {
} }
this->emitOutputSetup(); this->emitOutputSetup();
this->emitMainFunctionEnd(); this->emitFunctionEnd();
} }
@ -6107,7 +6123,7 @@ namespace dxvk {
m_module.opFunctionCall( m_module.opFunctionCall(
m_module.defVoidType(), m_module.defVoidType(),
m_cs.functionId, 0, nullptr); m_cs.functionId, 0, nullptr);
this->emitMainFunctionEnd(); this->emitFunctionEnd();
} }
@ -6212,9 +6228,10 @@ namespace dxvk {
uint32_t funId = m_module.allocateId(); uint32_t funId = m_module.allocateId();
m_module.functionBegin(m_module.defVoidType(), this->emitFunctionBegin(funId,
funId, funTypeId, spv::FunctionControlMaskNone); m_module.defVoidType(),
m_module.opLabel(m_module.allocateId()); funTypeId);
this->emitFunctionLabel();
DxbcCompilerHsControlPointPhase result; DxbcCompilerHsControlPointPhase result;
result.functionId = funId; result.functionId = funId;
@ -6230,9 +6247,10 @@ namespace dxvk {
uint32_t funId = m_module.allocateId(); uint32_t funId = m_module.allocateId();
m_module.setDebugName(funId, "hs_passthrough"); m_module.setDebugName(funId, "hs_passthrough");
m_module.functionBegin(m_module.defVoidType(), this->emitFunctionBegin(funId,
funId, funTypeId, spv::FunctionControlMaskNone); m_module.defVoidType(),
m_module.opLabel(m_module.allocateId()); funTypeId);
this->emitFunctionLabel();
// We'll basically copy each input variable to the corresponding // We'll basically copy each input variable to the corresponding
// output, using the shader's invocation ID as the array index. // output, using the shader's invocation ID as the array index.
@ -6270,8 +6288,7 @@ namespace dxvk {
} }
// End function // End function
m_module.opReturn(); this->emitFunctionEnd();
m_module.functionEnd();
DxbcCompilerHsControlPointPhase result; DxbcCompilerHsControlPointPhase result;
result.functionId = funId; result.functionId = funId;
@ -6286,11 +6303,12 @@ namespace dxvk {
uint32_t funId = m_module.allocateId(); uint32_t funId = m_module.allocateId();
m_module.functionBegin(m_module.defVoidType(), this->emitFunctionBegin(funId,
funId, funTypeId, spv::FunctionControlMaskNone); m_module.defVoidType(),
funTypeId);
uint32_t argId = m_module.functionParameter(argTypeId); uint32_t argId = m_module.functionParameter(argTypeId);
m_module.opLabel(m_module.allocateId()); this->emitFunctionLabel();
DxbcCompilerHsForkJoinPhase result; DxbcCompilerHsForkJoinPhase result;
result.functionId = funId; result.functionId = funId;

View File

@ -431,6 +431,11 @@ namespace dxvk {
// currently active if-else blocks and loops. // currently active if-else blocks and loops.
std::vector<DxbcCfgBlock> m_controlFlowBlocks; std::vector<DxbcCfgBlock> m_controlFlowBlocks;
//////////////////////////////////////////////
// Function state tracking. Required in order
// to properly end functions in some cases.
bool m_insideFunction = false;
/////////////////////////////////////////////// ///////////////////////////////////////////////
// Specialization constants. These are defined // Specialization constants. These are defined
// as needed by the getSpecConstant method. // as needed by the getSpecConstant method.
@ -1008,9 +1013,16 @@ namespace dxvk {
// Common function definition methods // Common function definition methods
void emitInit(); 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 // Shader initialization methods