mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-09 16:31:19 +12:00
138 lines
No EOL
4.4 KiB
C++
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();
|
|
} |