Skip to content

Commit

Permalink
fix for recompiler/interperter crash on arm
Browse files Browse the repository at this point in the history
"Don't reinvent the wheel"
  • Loading branch information
SSimco authored and exverge-0 committed Jul 11, 2024
1 parent e0d3e46 commit 7c0c613
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 170 deletions.
27 changes: 19 additions & 8 deletions src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,10 @@ uint32 LatteCP_readU32Deprc()
// no display list active
while (true)
{
gxRingBufferWritePtr = gx2WriteGatherPipe.writeGatherPtrGxBuffer[GX2::sGX2MainCoreIndex];
readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) {
gxRingBufferWritePtr = data.writeGatherPtrGxBuffer[GX2::sGX2MainCoreIndex];
readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
});
if (readDistance != 0)
break;

Expand All @@ -167,7 +169,9 @@ uint32 LatteCP_readU32Deprc()
}
LatteThread_HandleOSScreen(); // check if new frame was presented via OSScreen API

readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) {
readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
});
if (readDistance != 0)
break;
if (Latte_GetStopSignal())
Expand Down Expand Up @@ -198,8 +202,10 @@ void LatteCP_waitForNWords(uint32 numWords)
// no display list active
while (true)
{
gxRingBufferWritePtr = gx2WriteGatherPipe.writeGatherPtrGxBuffer[GX2::sGX2MainCoreIndex];
readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) {
gxRingBufferWritePtr = data.writeGatherPtrGxBuffer[GX2::sGX2MainCoreIndex];
readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
});
if (readDistance < 0)
return; // wrap around means there is at least one full command queued after this
if (readDistance >= waitDistance)
Expand All @@ -211,7 +217,9 @@ void LatteCP_waitForNWords(uint32 numWords)
{
_mm_pause();
}
readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) {
readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
});
if (readDistance < 0)
return; // wrap around means there is at least one full command queued after this
if (readDistance >= waitDistance)
Expand Down Expand Up @@ -779,8 +787,11 @@ LatteCMDPtr LatteCP_itHLEFifoWrapAround(LatteCMDPtr cmd, uint32 nWords)
{
cemu_assert_debug(nWords == 1);
uint32 unused = LatteReadCMD();
gxRingBufferReadPtr = gx2WriteGatherPipe.gxRingBuffer;
cmd = (LatteCMDPtr)gxRingBufferReadPtr;

gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) {
gxRingBufferReadPtr = data.gxRingBuffer;
cmd = (LatteCMDPtr)gxRingBufferReadPtr;
});
return cmd;
}

Expand Down
4 changes: 3 additions & 1 deletion src/Cafe/HW/Latte/Core/LatteThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ int Latte_ThreadEntry()
if (Latte_GetStopSignal())
LatteThread_Exit();
}
gxRingBufferReadPtr = gx2WriteGatherPipe.gxRingBuffer;
gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) {
gxRingBufferReadPtr = data.gxRingBuffer;
});
LatteCP_ProcessRingbuffer();
cemu_assert_debug(false); // should never reach
return 0;
Expand Down
80 changes: 43 additions & 37 deletions src/Cafe/OS/libs/gx2/GX2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,39 +332,43 @@ uint64 Latte_GetTime()

void _GX2SubmitToTCL()
{
uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance());
// do nothing if called from non-main GX2 core
if (GX2::sGX2MainCoreIndex != coreIndex)
{
cemuLog_logDebug(LogType::Force, "_GX2SubmitToTCL() called on non-main GX2 core");
return;
}
if( gx2WriteGatherPipe.displayListStart[coreIndex] != MPTR_NULL )
return; // quit if in display list
_GX2LastFlushPtr[coreIndex] = (gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex]);
// update last submitted CB timestamp
uint64 commandBufferTimestamp = Latte_GetTime();
LatteGPUState.lastSubmittedCommandBufferTimestamp.store(commandBufferTimestamp);
cemuLog_log(LogType::GX2, "Submitting GX2 command buffer with timestamp {:016x}", commandBufferTimestamp);
// submit HLE packet to write retirement timestamp
gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_SET_CB_RETIREMENT_TIMESTAMP, 2));
gx2WriteGather_submitU32AsBE((uint32)(commandBufferTimestamp>>32ULL));
gx2WriteGather_submitU32AsBE((uint32)(commandBufferTimestamp&0xFFFFFFFFULL));
gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) {
uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance());
// do nothing if called from non-main GX2 core
if (GX2::sGX2MainCoreIndex != coreIndex)
{
cemuLog_logDebug(LogType::Force, "_GX2SubmitToTCL() called on non-main GX2 core");
return;
}
if (data.displayListStart[coreIndex] != MPTR_NULL)
return; // quit if in display list
_GX2LastFlushPtr[coreIndex] = (data.writeGatherPtrGxBuffer[coreIndex]);
// update last submitted CB timestamp
uint64 commandBufferTimestamp = Latte_GetTime();
LatteGPUState.lastSubmittedCommandBufferTimestamp.store(commandBufferTimestamp);
cemuLog_log(LogType::GX2, "Submitting GX2 command buffer with timestamp {:016x}", commandBufferTimestamp);
// submit HLE packet to write retirement timestamp
gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_SET_CB_RETIREMENT_TIMESTAMP, 2));
gx2WriteGather_submitU32AsBE((uint32)(commandBufferTimestamp >> 32ULL));
gx2WriteGather_submitU32AsBE((uint32)(commandBufferTimestamp & 0xFFFFFFFFULL));
});
}

uint32 _GX2GetUnflushedBytes(uint32 coreIndex)
{
uint32 unflushedBytes = 0;
if (_GX2LastFlushPtr[coreIndex] != NULL)
{
if (_GX2LastFlushPtr[coreIndex] > gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex])
unflushedBytes = (uint32)(gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex] - gx2WriteGatherPipe.gxRingBuffer + 4); // this isn't 100% correct since we ignore the bytes between the last flush address and the start of the wrap around
return gx2WriteGatherPipe.accessDataRet<uint32>([&](GX2WriteGatherPipeStateData& data) {
uint32 unflushedBytes = 0;
if (_GX2LastFlushPtr[coreIndex] != NULL)
{
if (_GX2LastFlushPtr[coreIndex] > data.writeGatherPtrGxBuffer[coreIndex])
unflushedBytes = (uint32)(data.writeGatherPtrGxBuffer[coreIndex] - data.gxRingBuffer + 4); // this isn't 100% correct since we ignore the bytes between the last flush address and the start of the wrap around
else
unflushedBytes = (uint32)(data.writeGatherPtrGxBuffer[coreIndex] - _GX2LastFlushPtr[coreIndex]);
}
else
unflushedBytes = (uint32)(gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex] - _GX2LastFlushPtr[coreIndex]);
}
else
unflushedBytes = (uint32)(gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex] - gx2WriteGatherPipe.gxRingBuffer);
return unflushedBytes;
unflushedBytes = (uint32)(data.writeGatherPtrGxBuffer[coreIndex] - data.gxRingBuffer);
return unflushedBytes;
});
}

/*
Expand All @@ -373,15 +377,17 @@ uint32 _GX2GetUnflushedBytes(uint32 coreIndex)
*/
void GX2ReserveCmdSpace(uint32 reservedFreeSpaceInU32)
{
uint32 coreIndex = coreinit::OSGetCoreId();
// if we are in a display list then do nothing
if( gx2WriteGatherPipe.displayListStart[coreIndex] != MPTR_NULL )
return;
uint32 unflushedBytes = _GX2GetUnflushedBytes(coreIndex);
if( unflushedBytes >= 0x1000 )
{
_GX2SubmitToTCL();
}
gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) {
uint32 coreIndex = coreinit::OSGetCoreId();
// if we are in a display list then do nothing
if (data.displayListStart[coreIndex] != MPTR_NULL)
return;
uint32 unflushedBytes = _GX2GetUnflushedBytes(coreIndex);
if (unflushedBytes >= 0x1000)
{
_GX2SubmitToTCL();
}
});
}

void gx2_load()
Expand Down
Loading

0 comments on commit 7c0c613

Please sign in to comment.