From 7c0c61370090e8ab8786898e2a093c096e242134 Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Fri, 24 May 2024 12:49:59 +0300 Subject: [PATCH] fix for recompiler/interperter crash on arm "Don't reinvent the wheel" --- .../HW/Latte/Core/LatteCommandProcessor.cpp | 27 +- src/Cafe/HW/Latte/Core/LatteThread.cpp | 4 +- src/Cafe/OS/libs/gx2/GX2.cpp | 80 +++--- src/Cafe/OS/libs/gx2/GX2_Command.cpp | 268 ++++++++++-------- src/Cafe/OS/libs/gx2/GX2_Command.h | 40 ++- 5 files changed, 249 insertions(+), 170 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp index 167911b6a4..ab03ab2595 100644 --- a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp +++ b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp @@ -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; @@ -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()) @@ -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) @@ -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) @@ -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; } diff --git a/src/Cafe/HW/Latte/Core/LatteThread.cpp b/src/Cafe/HW/Latte/Core/LatteThread.cpp index 8874ecf45d..d5fd7647af 100644 --- a/src/Cafe/HW/Latte/Core/LatteThread.cpp +++ b/src/Cafe/HW/Latte/Core/LatteThread.cpp @@ -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; diff --git a/src/Cafe/OS/libs/gx2/GX2.cpp b/src/Cafe/OS/libs/gx2/GX2.cpp index c2ea34a4e6..184ec1dac9 100644 --- a/src/Cafe/OS/libs/gx2/GX2.cpp +++ b/src/Cafe/OS/libs/gx2/GX2.cpp @@ -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([&](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; + }); } /* @@ -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() diff --git a/src/Cafe/OS/libs/gx2/GX2_Command.cpp b/src/Cafe/OS/libs/gx2/GX2_Command.cpp index ec96a4ffc4..9ec5baeace 100644 --- a/src/Cafe/OS/libs/gx2/GX2_Command.cpp +++ b/src/Cafe/OS/libs/gx2/GX2_Command.cpp @@ -12,33 +12,39 @@ extern uint8* gxRingBufferReadPtr; -GX2WriteGatherPipeState gx2WriteGatherPipe = { 0 }; +GX2WriteGatherPipeState gx2WriteGatherPipe = { }; void gx2WriteGather_submitU32AsBE(uint32 v) { - uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); - if (gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex] == NULL) - return; - *(uint32*)(*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex]) = _swapEndianU32(v); - (*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex]) += 4; + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); + if (data.writeGatherPtrWrite[coreIndex] == NULL) + return; + *(uint32*)(*data.writeGatherPtrWrite[coreIndex]) = _swapEndianU32(v); + (*data.writeGatherPtrWrite[coreIndex]) += 4; + }); } void gx2WriteGather_submitU32AsLE(uint32 v) { - uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); - if (gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex] == NULL) - return; - *(uint32*)(*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex]) = v; - (*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex]) += 4; + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); + if (data.writeGatherPtrWrite[coreIndex] == NULL) + return; + *(uint32*)(*data.writeGatherPtrWrite[coreIndex]) = v; + (*data.writeGatherPtrWrite[coreIndex]) += 4; + }); } void gx2WriteGather_submitU32AsLEArray(uint32* v, uint32 numValues) { - uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); - if (gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex] == NULL) - return; - memcpy_dwords((*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex]), v, numValues); - (*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex]) += 4 * numValues; + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); + if (data.writeGatherPtrWrite[coreIndex] == NULL) + return; + memcpy_dwords((*data.writeGatherPtrWrite[coreIndex]), v, numValues); + (*data.writeGatherPtrWrite[coreIndex]) += 4 * numValues; + }); } namespace GX2 @@ -54,128 +60,156 @@ namespace GX2 void GX2Init_writeGather() // init write gather, make current core { - if (gx2WriteGatherPipe.gxRingBuffer == NULL) - gx2WriteGatherPipe.gxRingBuffer = (uint8*)malloc(GX2_COMMAND_RING_BUFFER_SIZE); - if (gx2WriteGatherCurrentMainCoreIndex == sGX2MainCoreIndex) - return; // write gather already configured for same core - for (sint32 i = 0; i < PPC_CORE_COUNT; i++) - { - if (i == sGX2MainCoreIndex) - { - gx2WriteGatherPipe.writeGatherPtrGxBuffer[i] = gx2WriteGatherPipe.gxRingBuffer; - gx2WriteGatherPipe.writeGatherPtrWrite[i] = &gx2WriteGatherPipe.writeGatherPtrGxBuffer[i]; - } - else + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + if (data.gxRingBuffer == NULL) + data.gxRingBuffer = (uint8*)malloc(GX2_COMMAND_RING_BUFFER_SIZE); + if (gx2WriteGatherCurrentMainCoreIndex == sGX2MainCoreIndex) + return; // write gather already configured for same core + for (sint32 i = 0; i < PPC_CORE_COUNT; i++) { - gx2WriteGatherPipe.writeGatherPtrGxBuffer[i] = NULL; - gx2WriteGatherPipe.writeGatherPtrWrite[i] = NULL; + if (i == sGX2MainCoreIndex) + { + data.writeGatherPtrGxBuffer[i] = data.gxRingBuffer; + data.writeGatherPtrWrite[i] = &data.writeGatherPtrGxBuffer[i]; + } + else + { + data.writeGatherPtrGxBuffer[i] = NULL; + data.writeGatherPtrWrite[i] = NULL; + } + data.displayListStart[i] = MPTR_NULL; + data.writeGatherPtrDisplayList[i] = NULL; + data.displayListMaxSize[i] = 0; } - gx2WriteGatherPipe.displayListStart[i] = MPTR_NULL; - gx2WriteGatherPipe.writeGatherPtrDisplayList[i] = NULL; - gx2WriteGatherPipe.displayListMaxSize[i] = 0; - } - gx2WriteGatherCurrentMainCoreIndex = sGX2MainCoreIndex; - gx2WriteGatherInited = true; + gx2WriteGatherCurrentMainCoreIndex = sGX2MainCoreIndex; + gx2WriteGatherInited = true; + }); } void GX2WriteGather_beginDisplayList(PPCInterpreter_t* hCPU, MPTR buffer, uint32 maxSize) { - uint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU); - gx2WriteGatherPipe.displayListStart[coreIndex] = buffer; - gx2WriteGatherPipe.displayListMaxSize[coreIndex] = maxSize; - // set new write gather ptr - gx2WriteGatherPipe.writeGatherPtrDisplayList[coreIndex] = memory_getPointerFromVirtualOffset(gx2WriteGatherPipe.displayListStart[coreIndex]); - gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex] = &gx2WriteGatherPipe.writeGatherPtrDisplayList[coreIndex]; + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU); + data.displayListStart[coreIndex] = buffer; + data.displayListMaxSize[coreIndex] = maxSize; + // set new write gather ptr + data.writeGatherPtrDisplayList[coreIndex] = memory_getPointerFromVirtualOffset(data.displayListStart[coreIndex]); + data.writeGatherPtrWrite[coreIndex] = &data.writeGatherPtrDisplayList[coreIndex]; + }); } uint32 GX2WriteGather_getDisplayListWriteDistance(sint32 coreIndex) { - return (uint32)(*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex] - memory_getPointerFromVirtualOffset(gx2WriteGatherPipe.displayListStart[coreIndex])); + return gx2WriteGatherPipe.accessDataRet([&](GX2WriteGatherPipeStateData& data) { + return (uint32)(*data.writeGatherPtrWrite[coreIndex] - memory_getPointerFromVirtualOffset(data.displayListStart[coreIndex])); + }); } uint32 GX2WriteGather_getFifoWriteDistance(uint32 coreIndex) { - uint32 writeDistance = (uint32)(gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex] - gx2WriteGatherPipe.gxRingBuffer); - return writeDistance; + return gx2WriteGatherPipe.accessDataRet([&](GX2WriteGatherPipeStateData& data) { + uint32 writeDistance = (uint32)(data.writeGatherPtrGxBuffer[coreIndex] - data.gxRingBuffer); + return writeDistance; + }); } uint32 GX2WriteGather_endDisplayList(PPCInterpreter_t* hCPU, MPTR buffer) { - uint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU); - if (gx2WriteGatherPipe.displayListStart[coreIndex] != MPTR_NULL) - { - uint32 currentWriteSize = GX2WriteGather_getDisplayListWriteDistance(coreIndex); - // pad to 32 byte - if (gx2WriteGatherPipe.displayListMaxSize[coreIndex] >= ((gx2WriteGatherPipe.displayListMaxSize[coreIndex] + 0x1F) & ~0x1F)) + return gx2WriteGatherPipe.accessDataRet([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU); + if (data.displayListStart[coreIndex] != MPTR_NULL) { - while ((currentWriteSize & 0x1F) != 0) + uint32 currentWriteSize = GX2WriteGather_getDisplayListWriteDistance(coreIndex); + // pad to 32 byte + if (data.displayListMaxSize[coreIndex] >= ((data.displayListMaxSize[coreIndex] + 0x1F) & ~0x1F)) { - gx2WriteGather_submitU32AsBE(pm4HeaderType2Filler()); - currentWriteSize += 4; + while ((currentWriteSize & 0x1F) != 0) + { + gx2WriteGather_submitU32AsBE(pm4HeaderType2Filler()); + currentWriteSize += 4; + } } + // get size of written data + currentWriteSize = GX2WriteGather_getDisplayListWriteDistance(coreIndex); + // disable current display list and restore write gather ptr + data.displayListStart[coreIndex] = MPTR_NULL; + if (sGX2MainCoreIndex == coreIndex) + data.writeGatherPtrWrite[coreIndex] = &data.writeGatherPtrGxBuffer[coreIndex]; + else + data.writeGatherPtrWrite[coreIndex] = NULL; + // return size of (written) display list + return currentWriteSize; } - // get size of written data - currentWriteSize = GX2WriteGather_getDisplayListWriteDistance(coreIndex); - // disable current display list and restore write gather ptr - gx2WriteGatherPipe.displayListStart[coreIndex] = MPTR_NULL; - if (sGX2MainCoreIndex == coreIndex) - gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex] = &gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex]; else - gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex] = NULL; - // return size of (written) display list - return currentWriteSize; - } - else - { - // no active display list - // return a size of 0 - return 0; - } + { + // no active display list + // return a size of 0 + return 0u; + } + }); } bool GX2GetCurrentDisplayList(betype* displayListAddr, uint32be* displayListSize) { - uint32 coreIndex = coreinit::OSGetCoreId(); - if (gx2WriteGatherPipe.displayListStart[coreIndex] == MPTR_NULL) - return false; - - if (displayListAddr) - *displayListAddr = gx2WriteGatherPipe.displayListStart[coreIndex]; - if (displayListSize) - *displayListSize = gx2WriteGatherPipe.displayListMaxSize[coreIndex]; - - return true; + return gx2WriteGatherPipe.accessDataRet([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = coreinit::OSGetCoreId(); + if (data.displayListStart[coreIndex] == MPTR_NULL) + return false; + + if (displayListAddr) + *displayListAddr = data.displayListStart[coreIndex]; + if (displayListSize) + *displayListSize = data.displayListMaxSize[coreIndex]; + + return true; + }); } bool GX2GetDisplayListWriteStatus() { - // returns true if we are writing to a display list - uint32 coreIndex = coreinit::OSGetCoreId(); - return gx2WriteGatherPipe.displayListStart[coreIndex] != MPTR_NULL; + return gx2WriteGatherPipe.accessDataRet([&](GX2WriteGatherPipeStateData& data) { + // returns true if we are writing to a display list + uint32 coreIndex = coreinit::OSGetCoreId(); + return data.displayListStart[coreIndex] != MPTR_NULL; + }); + } + + bool GX2WriteGather_isDisplayListActive() + { + return gx2WriteGatherPipe.accessDataRet([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = coreinit::OSGetCoreId(); + if (data.displayListStart[coreIndex] != MPTR_NULL) + return true; + return false; + }); } uint32 GX2WriteGather_getReadWriteDistance() { - uint32 coreIndex = sGX2MainCoreIndex; - uint32 writeDistance = (uint32)(gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex] + GX2_COMMAND_RING_BUFFER_SIZE - gxRingBufferReadPtr); - writeDistance %= GX2_COMMAND_RING_BUFFER_SIZE; - return writeDistance; + return gx2WriteGatherPipe.accessDataRet([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = sGX2MainCoreIndex; + uint32 writeDistance = (uint32)(data.writeGatherPtrGxBuffer[coreIndex] + GX2_COMMAND_RING_BUFFER_SIZE - gxRingBufferReadPtr); + writeDistance %= GX2_COMMAND_RING_BUFFER_SIZE; + return writeDistance; + }); } void GX2WriteGather_checkAndInsertWrapAroundMark() { - uint32 coreIndex = coreinit::OSGetCoreId(); - if (coreIndex != sGX2MainCoreIndex) // only if main gx2 core - return; - if (gx2WriteGatherPipe.displayListStart[coreIndex] != MPTR_NULL) - return; - uint32 writeDistance = GX2WriteGather_getFifoWriteDistance(coreIndex); - if (writeDistance >= (GX2_COMMAND_RING_BUFFER_SIZE * 3 / 5)) - { - gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_FIFO_WRAP_AROUND, 1)); - gx2WriteGather_submitU32AsBE(0); // empty word since we can't send commands with zero data words - gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex] = gx2WriteGatherPipe.gxRingBuffer; - } + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = coreinit::OSGetCoreId(); + if (coreIndex != sGX2MainCoreIndex) // only if main gx2 core + return; + if (data.displayListStart[coreIndex] != MPTR_NULL) + return; + uint32 writeDistance = GX2WriteGather_getFifoWriteDistance(coreIndex); + if (writeDistance >= (GX2_COMMAND_RING_BUFFER_SIZE * 3 / 5)) + { + gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_FIFO_WRAP_AROUND, 1)); + gx2WriteGather_submitU32AsBE(0); // empty word since we can't send commands with zero data words + data.writeGatherPtrGxBuffer[coreIndex] = data.gxRingBuffer; + } + }); } void GX2BeginDisplayList(MEMPTR displayListAddr, uint32 size) @@ -209,23 +243,25 @@ namespace GX2 void GX2DirectCallDisplayList(void* addr, uint32 size) { - // this API submits to TCL directly and bypasses write-gatherer - // its basically a way to manually submit a command buffer to the GPU - // as such it also affects the submission and retire timestamps - - uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); - cemu_assert_debug(coreIndex == sGX2MainCoreIndex); - coreIndex = sGX2MainCoreIndex; // always submit to main queue which is owned by GX2 main core (TCLSubmitToRing does not need this workaround) - - uint32be* cmdStream = (uint32be*)(gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex]); - cmdStream[0] = pm4HeaderType3(IT_INDIRECT_BUFFER_PRIV, 3); - cmdStream[1] = memory_virtualToPhysical(MEMPTR(addr).GetMPTR()); - cmdStream[2] = 0; - cmdStream[3] = size / 4; - gx2WriteGatherPipe.writeGatherPtrGxBuffer[coreIndex] += 16; - - // update submission timestamp and retired timestamp - _GX2SubmitToTCL(); + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + // this API submits to TCL directly and bypasses write-gatherer + // its basically a way to manually submit a command buffer to the GPU + // as such it also affects the submission and retire timestamps + + uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); + cemu_assert_debug(coreIndex == sGX2MainCoreIndex); + coreIndex = sGX2MainCoreIndex; // always submit to main queue which is owned by GX2 main core (TCLSubmitToRing does not need this workaround) + + uint32be* cmdStream = (uint32be*)(data.writeGatherPtrGxBuffer[coreIndex]); + cmdStream[0] = pm4HeaderType3(IT_INDIRECT_BUFFER_PRIV, 3); + cmdStream[1] = memory_virtualToPhysical(MEMPTR(addr).GetMPTR()); + cmdStream[2] = 0; + cmdStream[3] = size / 4; + data.writeGatherPtrGxBuffer[coreIndex] += 16; + + // update submission timestamp and retired timestamp + _GX2SubmitToTCL(); + }); } void GX2CopyDisplayList(MEMPTR addr, uint32 size) diff --git a/src/Cafe/OS/libs/gx2/GX2_Command.h b/src/Cafe/OS/libs/gx2/GX2_Command.h index 51c049289f..9ddb53d2ae 100644 --- a/src/Cafe/OS/libs/gx2/GX2_Command.h +++ b/src/Cafe/OS/libs/gx2/GX2_Command.h @@ -2,7 +2,7 @@ #include "Cafe/HW/Latte/ISA/LatteReg.h" #include "Cafe/HW/Espresso/Const.h" -struct GX2WriteGatherPipeState +struct GX2WriteGatherPipeStateData { uint8* gxRingBuffer; // each core has it's own write gatherer and display list state (writing) @@ -13,6 +13,26 @@ struct GX2WriteGatherPipeState uint32 displayListMaxSize[Espresso::CORE_COUNT]; }; +struct GX2WriteGatherPipeState +{ + template + inline void accessData(Fn fn) + { + std::lock_guard lock(_mutex); + fn(_data); + } + template + inline T accessDataRet(Fn fn) + { + std::lock_guard lock(_mutex); + return fn(_data); + } + + private: + std::recursive_mutex _mutex; + GX2WriteGatherPipeStateData _data = {}; +}; + extern GX2WriteGatherPipeState gx2WriteGatherPipe; void GX2ReserveCmdSpace(uint32 reservedFreeSpaceInU32); // move to GX2 namespace eventually @@ -27,7 +47,9 @@ uint32 PPCInterpreter_getCurrentCoreIndex(); template inline void gx2WriteGather_submit_(uint32 coreIndex, uint32be* writePtr) { - (*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex]) = (uint8*)writePtr; + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + (*data.writeGatherPtrWrite[coreIndex]) = (uint8*)writePtr; + }); } template @@ -74,12 +96,14 @@ gx2WriteGather_submit_(uint32 coreIndex, uint32be* writePtr, const T& arg, Targs template inline void gx2WriteGather_submit(Targs... args) { - uint32 coreIndex = PPCInterpreter_getCurrentCoreIndex(); - if (gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex] == nullptr) - return; - - uint32be* writePtr = (uint32be*)(*gx2WriteGatherPipe.writeGatherPtrWrite[coreIndex]); - gx2WriteGather_submit_(coreIndex, writePtr, std::forward(args)...); + gx2WriteGatherPipe.accessData([&](GX2WriteGatherPipeStateData& data) { + uint32 coreIndex = PPCInterpreter_getCurrentCoreIndex(); + if (data.writeGatherPtrWrite[coreIndex] == nullptr) + return; + + uint32be* writePtr = (uint32be*)(*data.writeGatherPtrWrite[coreIndex]); + gx2WriteGather_submit_(coreIndex, writePtr, std::forward(args)...); + }); } namespace GX2