[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) {
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;

View File

@ -431,6 +431,11 @@ namespace dxvk {
// currently active if-else blocks and loops.
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
// 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