Latte: Widen conditions for fast draw mode

This commit is contained in:
Exzap 2026-06-14 21:50:02 +02:00
parent 1c7fbafb00
commit 038781a05e

View File

@ -330,19 +330,18 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
return cmd; return cmd;
} }
// similar to LatteCP_itSetRegistersGeneric, but calls a callback for every register range checked and returns true ONLY if any register value has actually changed (e.g. not updated to the same value as before)
template<uint32 TRegisterBase, typename TRegRangeCallback> template<uint32 TRegisterBase, typename TRegRangeCallback>
LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords, TRegRangeCallback cbRegRange) bool LatteCP_itSetRegistersGeneric2(LatteCMDPtr cmd, uint32 nWords, TRegRangeCallback cbRegRange)
{ {
uint32 registerOffset = LatteReadCMD(); const uint32 registerOffset = LatteReadCMD();
uint32 registerIndex = TRegisterBase + registerOffset; const uint32 registerIndex = TRegisterBase + registerOffset;
uint32 registerStartIndex = registerIndex; const uint32 registerStartIndex = registerIndex;
uint32 registerEndIndex = registerStartIndex + nWords; const uint32 registerEndIndex = registerStartIndex + nWords;
#ifdef CEMU_DEBUG_ASSERT
cemu_assert_debug((registerIndex + nWords) <= LATTE_MAX_REGISTER); cemu_assert_debug((registerIndex + nWords) <= LATTE_MAX_REGISTER);
#endif
cbRegRange(registerStartIndex, registerEndIndex);
uint32* outputReg = (uint32*)(LatteGPUState.contextRegister + registerIndex); uint32* outputReg = (uint32*)(LatteGPUState.contextRegister + registerIndex);
bool hasRegChange = false;
if (LatteGPUState.contextControl0 == 0x80000077) if (LatteGPUState.contextControl0 == 0x80000077)
{ {
// state shadowing enabled // state shadowing enabled
@ -354,6 +353,7 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords, TRegRa
MPTR regShadowAddr = shadowAddrs[indexCounter]; MPTR regShadowAddr = shadowAddrs[indexCounter];
if (regShadowAddr) if (regShadowAddr)
*(uint32*)(memory_base + regShadowAddr) = _swapEndianU32(dataWord); *(uint32*)(memory_base + regShadowAddr) = _swapEndianU32(dataWord);
hasRegChange |= (outputReg[indexCounter] != dataWord);
outputReg[indexCounter] = dataWord; outputReg[indexCounter] = dataWord;
indexCounter++; indexCounter++;
} }
@ -364,13 +364,17 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords, TRegRa
sint32 indexCounter = 0; sint32 indexCounter = 0;
while (--nWords) while (--nWords)
{ {
*outputReg = LatteReadCMD(); uint32 dataWord = LatteReadCMD();
hasRegChange |= (*outputReg != dataWord);
*outputReg = dataWord;
outputReg++; outputReg++;
} }
} }
// some register writes trigger special behavior // some register writes trigger special behavior
LatteCP_itSetRegistersGeneric_handleSpecialRanges<TRegisterBase>(registerStartIndex, registerEndIndex); LatteCP_itSetRegistersGeneric_handleSpecialRanges<TRegisterBase>(registerStartIndex, registerEndIndex);
return cmd; // callback
cbRegRange(registerStartIndex, registerEndIndex, hasRegChange);
return hasRegChange;
} }
LatteCMDPtr LatteCP_itIndexType(LatteCMDPtr cmd, uint32 nWords) LatteCMDPtr LatteCP_itIndexType(LatteCMDPtr cmd, uint32 nWords)
@ -973,6 +977,7 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
LatteCMDPtr cmd, cmdStart, cmdEnd; LatteCMDPtr cmd, cmdStart, cmdEnd;
if (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd)) if (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd))
{ {
// cemuLog_log(LogType::Force, "[FastDrawMode] End due running out of commands");
drawPassCtx.endDrawPass(); drawPassCtx.endDrawPass();
return; return;
} }
@ -992,16 +997,28 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
{ {
case IT_SET_RESOURCE: // attribute buffers, uniform buffers or texture units case IT_SET_RESOURCE: // attribute buffers, uniform buffers or texture units
{ {
LatteCP_itSetRegistersGeneric<LATTE_REG_BASE_RESOURCE>(cmdData, nWords, [&drawPassCtx](uint32 registerStart, uint32 registerEnd) LatteCP_itSetRegistersGeneric2<LATTE_REG_BASE_RESOURCE>(cmdData, nWords, [&drawPassCtx](uint32 registerStart, uint32 registerEnd, bool regValuesChanged)
{ {
if ((registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)) || if ((registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)) ||
(registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)) || (registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)) ||
(registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7))) (registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)))
drawPassCtx.endDrawPass(); // texture updates end the current draw sequence {
if (regValuesChanged)
{
// cemuLog_log(LogType::Force, "[FastDrawMode] End due to texture change");
drawPassCtx.endDrawPass(); // texture updates end the current draw sequence
}
}
else if (registerStart >= mmSQ_VTX_ATTRIBUTE_BLOCK_START && registerEnd <= mmSQ_VTX_ATTRIBUTE_BLOCK_END) else if (registerStart >= mmSQ_VTX_ATTRIBUTE_BLOCK_START && registerEnd <= mmSQ_VTX_ATTRIBUTE_BLOCK_END)
drawPassCtx.notifyModifiedVertexBuffer(); {
if (regValuesChanged)
drawPassCtx.notifyModifiedVertexBuffer();
}
else else
drawPassCtx.notifyModifiedUniformBuffer(); {
if (regValuesChanged)
drawPassCtx.notifyModifiedUniformBuffer();
}
}); });
if (!drawPassCtx.isWithinDrawPass()) if (!drawPassCtx.isWithinDrawPass())
{ {
@ -1042,9 +1059,18 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
} }
case IT_SET_CONTEXT_REG: case IT_SET_CONTEXT_REG:
{ {
drawPassCtx.endDrawPass(); // LatteCP_itSetRegistersGeneric<LATTE_REG_BASE_CONTEXT>(cmd, nWords);
drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd); bool hasChanged = LatteCP_itSetRegistersGeneric2<LATTE_REG_BASE_CONTEXT>(cmdData, nWords, [](uint32 registerStart, uint32 registerEnd, bool regValuesChanged){});
return; //cemuLog_log(LogType::Force, "[FastDrawMode] Potential end due to SetContextReg (itHeader {:08x} data {:08x}) -> HasChanged {}", itHeader, (uint32)cmdData[0], hasChanged);
// drawPassCtx.endDrawPass();
// drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);
if (hasChanged)
{
drawPassCtx.endDrawPass();
drawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);
return;
}
break;
} }
case IT_INDIRECT_BUFFER_PRIV: case IT_INDIRECT_BUFFER_PRIV:
{ {
@ -1052,13 +1078,25 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
LatteCP_itIndirectBuffer(cmdData, nWords, drawPassCtx); LatteCP_itIndirectBuffer(cmdData, nWords, drawPassCtx);
if (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd)) // switch to sub buffer if (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd)) // switch to sub buffer
cemu_assert_debug(false); cemu_assert_debug(false);
break;
//if (!drawPassCtx.isWithinDrawPass()) }
// return cmdData; case IT_SET_SAMPLER:
{
bool hasChanged = LatteCP_itSetRegistersGeneric2<LATTE_REG_BASE_SAMPLER>(cmdData, nWords, [](uint32 registerStart, uint32 registerEnd, bool regValuesChanged){});
//cemuLog_log(LogType::Force, "[FastDrawMode] Set sampler (reg change = {} - filtered)", hasChanged);
if (hasChanged)
{
//cemuLog_log(LogType::Force, "[FastDrawMode] End due to sampler change");
drawPassCtx.endDrawPass();
drawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);
return;
}
break; break;
} }
default: default:
// unsupported command for fast draw // unsupported command for fast draw
//cemuLog_log(LogType::Force, "[FastDrawMode] Unallowed command. Data: {:08x} {:08x} {:08x} {:08x} {:08x} {:08x}", (uint32)itHeader, (uint32)cmdData[0], (uint32)cmdData[1], (uint32)cmdData[2], (uint32)cmdData[3], (uint32)cmdData[4], (uint32)cmdData[5]);
//cemuLog_log(LogType::Force, "[FastDrawMode] End due to unallowed packet 0x{:08x}", itHeader);
drawPassCtx.endDrawPass(); drawPassCtx.endDrawPass();
drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd); drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);
return; return;
@ -1071,6 +1109,7 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
else else
{ {
// unsupported command for fast draw // unsupported command for fast draw
//cemuLog_log(LogType::Force, "[FastDrawMode] End due to uknown packet 0x{:08x}", itHeader);
drawPassCtx.endDrawPass(); drawPassCtx.endDrawPass();
drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd); drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);
return; return;
@ -1167,6 +1206,7 @@ void LatteCP_processCommandBuffer(DrawPassContext& drawPassCtx)
case IT_DRAW_INDEX_2: case IT_DRAW_INDEX_2:
{ {
drawPassCtx.beginDrawPass(); drawPassCtx.beginDrawPass();
//cemuLog_log(LogType::Force, "[CmdBuf] DrawIndex2");
LatteCP_itDrawIndex2(cmdData, nWords, drawPassCtx); LatteCP_itDrawIndex2(cmdData, nWords, drawPassCtx);
// enter fast draw mode // enter fast draw mode
drawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd); drawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);
@ -1179,6 +1219,7 @@ void LatteCP_processCommandBuffer(DrawPassContext& drawPassCtx)
case IT_DRAW_INDEX_AUTO: case IT_DRAW_INDEX_AUTO:
{ {
drawPassCtx.beginDrawPass(); drawPassCtx.beginDrawPass();
//cemuLog_log(LogType::Force, "[CmdBuf] DrawIndexAuto");
LatteCP_itDrawIndexAuto(cmdData, nWords, drawPassCtx); LatteCP_itDrawIndexAuto(cmdData, nWords, drawPassCtx);
// enter fast draw mode // enter fast draw mode
drawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd); drawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);
@ -1192,6 +1233,7 @@ void LatteCP_processCommandBuffer(DrawPassContext& drawPassCtx)
{ {
DrawPassContext drawPassCtx; DrawPassContext drawPassCtx;
drawPassCtx.beginDrawPass(); drawPassCtx.beginDrawPass();
//cemuLog_log(LogType::Force, "[CmdBuf] DrawIndexImm");
LatteCP_itDrawImmediate(cmdData, nWords, drawPassCtx); LatteCP_itDrawImmediate(cmdData, nWords, drawPassCtx);
drawPassCtx.endDrawPass(); drawPassCtx.endDrawPass();
break; break;
@ -1448,6 +1490,7 @@ void LatteCP_ProcessRingbuffer()
{ {
DrawPassContext drawPassCtx; DrawPassContext drawPassCtx;
drawPassCtx.beginDrawPass(); drawPassCtx.beginDrawPass();
cemuLog_log(LogType::Force, "[TopLevel] DrawIndex2");
LatteCP_itDrawIndex2(cmd, nWords, drawPassCtx); LatteCP_itDrawIndex2(cmd, nWords, drawPassCtx);
drawPassCtx.endDrawPass(); drawPassCtx.endDrawPass();
timerRecheck += CP_TIMER_RECHECK / 64; timerRecheck += CP_TIMER_RECHECK / 64;
@ -1457,6 +1500,7 @@ void LatteCP_ProcessRingbuffer()
{ {
DrawPassContext drawPassCtx; DrawPassContext drawPassCtx;
drawPassCtx.beginDrawPass(); drawPassCtx.beginDrawPass();
cemuLog_log(LogType::Force, "[TopLevel] DrawIndexAuto");
LatteCP_itDrawIndexAuto(cmd, nWords, drawPassCtx); LatteCP_itDrawIndexAuto(cmd, nWords, drawPassCtx);
drawPassCtx.endDrawPass(); drawPassCtx.endDrawPass();
timerRecheck += CP_TIMER_RECHECK / 512; timerRecheck += CP_TIMER_RECHECK / 512;
@ -1466,6 +1510,7 @@ void LatteCP_ProcessRingbuffer()
{ {
DrawPassContext drawPassCtx; DrawPassContext drawPassCtx;
drawPassCtx.beginDrawPass(); drawPassCtx.beginDrawPass();
cemuLog_log(LogType::Force, "[TopLevel] DrawIndexImm");
LatteCP_itDrawImmediate(cmd, nWords, drawPassCtx); LatteCP_itDrawImmediate(cmd, nWords, drawPassCtx);
drawPassCtx.endDrawPass(); drawPassCtx.endDrawPass();
timerRecheck += CP_TIMER_RECHECK / 64; timerRecheck += CP_TIMER_RECHECK / 64;