Cemu/src/Cafe/HW/Latte/Core/LatteAsyncCommands.cpp
2022-08-22 22:21:23 +02:00

138 lines
No EOL
4.4 KiB
C++

#include "Cafe/HW/Latte/Core/Latte.h"
#include "Cafe/HW/Latte/Core/LatteAsyncCommands.h"
#include "Cafe/HW/Latte/Core/LatteShader.h"
#include "Cafe/HW/Latte/Core/LatteTexture.h"
void LatteThread_Exit();
SlimRWLock swl_gpuAsyncCommands;
typedef struct
{
uint32 type;
union
{
struct
{
MPTR physAddr;
MPTR mipAddr;
uint32 swizzle;
sint32 format;
sint32 width;
sint32 height;
sint32 depth;
uint32 pitch;
uint32 slice;
sint32 dim;
Latte::E_HWTILEMODE tilemode;
sint32 aa;
sint32 level;
}forceTextureReadback;
struct
{
uint64 shaderBaseHash;
uint64 shaderAuxHash;
LatteConst::ShaderType shaderType;
}deleteShader;
};
}LatteAsyncCommand_t;
#define ASYNC_CMD_FORCE_TEXTURE_READBACK 1
#define ASYNC_CMD_DELETE_SHADER 2
std::queue<LatteAsyncCommand_t> LatteAsyncCommandQueue;
void LatteAsyncCommands_queueForceTextureReadback(MPTR physAddr, MPTR mipAddr, uint32 swizzle, sint32 format, sint32 width, sint32 height, sint32 depth, uint32 pitch, uint32 slice, sint32 dim, Latte::E_HWTILEMODE tilemode, sint32 aa, sint32 level)
{
LatteAsyncCommand_t asyncCommand = {};
// setup command
asyncCommand.type = ASYNC_CMD_FORCE_TEXTURE_READBACK;
asyncCommand.forceTextureReadback.physAddr = physAddr;
asyncCommand.forceTextureReadback.mipAddr = mipAddr;
asyncCommand.forceTextureReadback.swizzle = swizzle;
asyncCommand.forceTextureReadback.format = format;
asyncCommand.forceTextureReadback.width = width;
asyncCommand.forceTextureReadback.height = height;
asyncCommand.forceTextureReadback.depth = depth;
asyncCommand.forceTextureReadback.pitch = pitch;
asyncCommand.forceTextureReadback.slice = slice;
asyncCommand.forceTextureReadback.dim = dim;
asyncCommand.forceTextureReadback.tilemode = tilemode;
asyncCommand.forceTextureReadback.aa = aa;
asyncCommand.forceTextureReadback.level = level;
swl_gpuAsyncCommands.LockWrite();
LatteAsyncCommandQueue.push(asyncCommand);
swl_gpuAsyncCommands.UnlockWrite();
}
void LatteAsyncCommands_queueDeleteShader(uint64 shaderBaseHash, uint64 shaderAuxHash, LatteConst::ShaderType shaderType)
{
LatteAsyncCommand_t asyncCommand = {};
// setup command
asyncCommand.type = ASYNC_CMD_DELETE_SHADER;
asyncCommand.deleteShader.shaderBaseHash = shaderBaseHash;
asyncCommand.deleteShader.shaderAuxHash = shaderAuxHash;
asyncCommand.deleteShader.shaderType = shaderType;
swl_gpuAsyncCommands.LockWrite();
LatteAsyncCommandQueue.push(asyncCommand);
swl_gpuAsyncCommands.UnlockWrite();
}
void LatteAsyncCommands_waitUntilAllProcessed()
{
while (LatteAsyncCommandQueue.empty() == false)
{
_mm_pause();
}
}
/*
* Called by the GPU command processor frequently
*/
void LatteAsyncCommands_checkAndExecute()
{
// quick check if queue is empty (requires no lock)
if (!Latte_IsActive())
LatteThread_Exit();
if (LatteAsyncCommandQueue.empty())
return;
swl_gpuAsyncCommands.LockWrite();
while (LatteAsyncCommandQueue.empty() == false)
{
// get first command in queue
LatteAsyncCommand_t asyncCommand = LatteAsyncCommandQueue.front();
swl_gpuAsyncCommands.UnlockWrite();
if (asyncCommand.type == ASYNC_CMD_FORCE_TEXTURE_READBACK)
{
cemu_assert_debug(asyncCommand.forceTextureReadback.level == 0); // implement mip swizzle and verify
LatteTextureView* textureView = LatteTC_GetTextureSliceViewOrTryCreate(asyncCommand.forceTextureReadback.physAddr, asyncCommand.forceTextureReadback.mipAddr, (Latte::E_GX2SURFFMT)asyncCommand.forceTextureReadback.format, asyncCommand.forceTextureReadback.tilemode, asyncCommand.forceTextureReadback.width, asyncCommand.forceTextureReadback.height, asyncCommand.forceTextureReadback.depth, asyncCommand.forceTextureReadback.pitch, 0, asyncCommand.forceTextureReadback.slice, asyncCommand.forceTextureReadback.level);
if (textureView != nullptr)
{
LatteTexture_UpdateDataToLatest(textureView->baseTexture);
// start transfer
LatteTextureReadback_StartTransfer(textureView);
// wait until finished
LatteTextureReadback_UpdateFinishedTransfers(true);
}
else
{
forceLogDebug_printf("Texture not found for readback");
}
}
else if (asyncCommand.type == ASYNC_CMD_DELETE_SHADER)
{
LatteSHRC_RemoveFromCacheByHash(asyncCommand.deleteShader.shaderBaseHash, asyncCommand.deleteShader.shaderAuxHash, asyncCommand.deleteShader.shaderType);
}
else
{
cemu_assert_unimplemented();
}
swl_gpuAsyncCommands.LockWrite();
LatteAsyncCommandQueue.pop();
}
swl_gpuAsyncCommands.UnlockWrite();
}