Skip to content

Commit

Permalink
Latte: Add support for LOOP_START_NO_AL shader instruction
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Exzap committed Mar 27, 2024
1 parent 42122b6 commit 63bf4e7
Show file tree
Hide file tree
Showing 6 changed files with 16 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ uint8 LatteMRT::GetActiveColorBufferMask(const LatteDecompilerShader* pixelShade
return 0;
cemu_assert_debug(colorControlReg.get_DEGAMMA_ENABLE() == false); // not supported
// 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)
uint32 channelTargetMask = lcr.CB_TARGET_MASK.get_MASK();
for (uint32 i = 0; i < 8; i++)
Expand Down
2 changes: 1 addition & 1 deletion src/Cafe/HW/Latte/Core/LatteShaderAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#define GPU7_CF_INST_VTX (0x02) // used only in GS copy program?
#define GPU7_CF_INST_LOOP_END (0x05)
#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_JUMP (0x0A)
Expand Down
6 changes: 4 additions & 2 deletions src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ bool LatteDecompiler_ParseCFInstruction(LatteDecompilerShaderContext* shaderCont
// ignored (we use ALU/IF/ELSE/PUSH/POP clauses to determine code flow)
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();
// set type and address
Expand Down Expand Up @@ -966,7 +967,8 @@ void LatteDecompiler_ParseClauses(LatteDecompilerShaderContext* decompilerContex
{
// 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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,8 @@ void LatteDecompiler_analyzeSubroutine(LatteDecompilerShaderContext* shaderConte
{
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;
}
Expand Down Expand Up @@ -685,7 +686,8 @@ void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteD
{
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.hasLoops = true;
Expand Down Expand Up @@ -929,7 +931,8 @@ void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteD
if (cfCurrentStackDepth < 0)
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
cfInstruction.activeStackDepth = cfCurrentStackDepth;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
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
// if pixel is disabled, then skip loop
Expand Down
4 changes: 2 additions & 2 deletions src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1284,9 +1284,9 @@ void VulkanRenderer::draw_beginSequence()

// update shader state
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;
cemu_assert_debug(false);
return;
Expand Down

0 comments on commit 63bf4e7

Please sign in to comment.