Latte: Add support for LOOP_START_NO_AL shader instruction

This instruction is used by Injustice: Gods Among Us and Project Zero

Also improved robustness of rendering to be less prone to crashing when a game tries to draw with broken shaders
This commit is contained in:
Exzap 2024-03-27 16:01:44 +01:00
parent 60adc38205
commit fa8bab2f39
6 changed files with 16 additions and 10 deletions

View File

@ -340,7 +340,7 @@ uint8 LatteMRT::GetActiveColorBufferMask(const LatteDecompilerShader* pixelShade
return 0; return 0;
cemu_assert_debug(colorControlReg.get_DEGAMMA_ENABLE() == false); // not supported cemu_assert_debug(colorControlReg.get_DEGAMMA_ENABLE() == false); // not supported
// combine color buffer mask with pixel output mask from pixel shader // combine color buffer mask with pixel output mask from pixel shader
colorBufferMask &= pixelShader->pixelColorOutputMask; colorBufferMask &= (pixelShader ? pixelShader->pixelColorOutputMask : 0);
// combine color buffer mask with color channel mask from mmCB_TARGET_MASK (disable render buffer if all colors are blocked) // combine color buffer mask with color channel mask from mmCB_TARGET_MASK (disable render buffer if all colors are blocked)
uint32 channelTargetMask = lcr.CB_TARGET_MASK.get_MASK(); uint32 channelTargetMask = lcr.CB_TARGET_MASK.get_MASK();
for (uint32 i = 0; i < 8; i++) for (uint32 i = 0; i < 8; i++)

View File

@ -12,7 +12,7 @@
#define GPU7_CF_INST_VTX (0x02) // used only in GS copy program? #define GPU7_CF_INST_VTX (0x02) // used only in GS copy program?
#define GPU7_CF_INST_LOOP_END (0x05) #define GPU7_CF_INST_LOOP_END (0x05)
#define GPU7_CF_INST_LOOP_START_DX10 (0x06) #define GPU7_CF_INST_LOOP_START_DX10 (0x06)
#define GPU7_CF_INST_LOOP_START_NO_AL (0x07) // (Seen in Project Zero) #define GPU7_CF_INST_LOOP_START_NO_AL (0x07) // (Seen in Project Zero, Injustice: Gods Among Us)
#define GPU7_CF_INST_LOOP_BREAK (0x09) #define GPU7_CF_INST_LOOP_BREAK (0x09)
#define GPU7_CF_INST_JUMP (0x0A) #define GPU7_CF_INST_JUMP (0x0A)

View File

@ -101,7 +101,8 @@ bool LatteDecompiler_ParseCFInstruction(LatteDecompilerShaderContext* shaderCont
// ignored (we use ALU/IF/ELSE/PUSH/POP clauses to determine code flow) // ignored (we use ALU/IF/ELSE/PUSH/POP clauses to determine code flow)
return true; return true;
} }
else if (cf_inst23_7 == GPU7_CF_INST_LOOP_START_DX10 || cf_inst23_7 == GPU7_CF_INST_LOOP_END) else if (cf_inst23_7 == GPU7_CF_INST_LOOP_START_DX10 || cf_inst23_7 == GPU7_CF_INST_LOOP_END ||
cf_inst23_7 == GPU7_CF_INST_LOOP_START_NO_AL)
{ {
LatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back(); LatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();
// set type and address // set type and address
@ -966,7 +967,8 @@ void LatteDecompiler_ParseClauses(LatteDecompilerShaderContext* decompilerContex
{ {
// no sub-instructions // no sub-instructions
} }
else if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END) else if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END ||
cfInstruction.type == GPU7_CF_INST_LOOP_START_NO_AL)
{ {
// no sub-instructions // no sub-instructions
} }

View File

@ -441,7 +441,8 @@ void LatteDecompiler_analyzeSubroutine(LatteDecompilerShaderContext* shaderConte
{ {
shaderContext->analyzer.modifiesPixelActiveState = true; shaderContext->analyzer.modifiesPixelActiveState = true;
} }
else if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END) else if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END ||
cfInstruction.type == GPU7_CF_INST_LOOP_START_NO_AL)
{ {
shaderContext->analyzer.modifiesPixelActiveState = true; shaderContext->analyzer.modifiesPixelActiveState = true;
} }
@ -685,7 +686,8 @@ void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteD
{ {
shaderContext->analyzer.modifiesPixelActiveState = true; shaderContext->analyzer.modifiesPixelActiveState = true;
} }
else if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END) else if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END ||
cfInstruction.type == GPU7_CF_INST_LOOP_START_NO_AL)
{ {
shaderContext->analyzer.modifiesPixelActiveState = true; shaderContext->analyzer.modifiesPixelActiveState = true;
shaderContext->analyzer.hasLoops = true; shaderContext->analyzer.hasLoops = true;
@ -929,7 +931,8 @@ void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteD
if (cfCurrentStackDepth < 0) if (cfCurrentStackDepth < 0)
debugBreakpoint(); debugBreakpoint();
} }
else if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END) else if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END ||
cfInstruction.type == GPU7_CF_INST_LOOP_START_NO_AL)
{ {
// no effect on stack depth // no effect on stack depth
cfInstruction.activeStackDepth = cfCurrentStackDepth; cfInstruction.activeStackDepth = cfCurrentStackDepth;

View File

@ -3662,7 +3662,8 @@ void LatteDecompiler_emitClauseCode(LatteDecompilerShaderContext* shaderContext,
{ {
src->addFmt("{} = {} == true && {} == true;" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - cfInstruction->popCount), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth - cfInstruction->popCount), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth - cfInstruction->popCount)); src->addFmt("{} = {} == true && {} == true;" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - cfInstruction->popCount), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth - cfInstruction->popCount), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth - cfInstruction->popCount));
} }
else if( cfInstruction->type == GPU7_CF_INST_LOOP_START_DX10 ) else if( cfInstruction->type == GPU7_CF_INST_LOOP_START_DX10 ||
cfInstruction->type == GPU7_CF_INST_LOOP_START_NO_AL)
{ {
// start of loop // start of loop
// if pixel is disabled, then skip loop // if pixel is disabled, then skip loop

View File

@ -1285,9 +1285,9 @@ void VulkanRenderer::draw_beginSequence()
// update shader state // update shader state
LatteSHRC_UpdateActiveShaders(); LatteSHRC_UpdateActiveShaders();
if (m_state.drawSequenceSkip) if (LatteGPUState.activeShaderHasError)
{ {
debug_printf("Skipping drawcalls due to shader error\n"); cemuLog_logDebugOnce(LogType::Force, "Skipping drawcalls due to shader error");
m_state.drawSequenceSkip = true; m_state.drawSequenceSkip = true;
cemu_assert_debug(false); cemu_assert_debug(false);
return; return;