mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-10 01:24:41 -06:00
Latte: Simplify code
This commit is contained in:
parent
3923bfcc01
commit
57bc919e7c
@ -76,12 +76,12 @@ struct LatteDrawcallContext
|
|||||||
{
|
{
|
||||||
bool isFirst{}; // first _execute() in current sequence
|
bool isFirst{}; // first _execute() in current sequence
|
||||||
// these are only valid if isFirst is false:
|
// these are only valid if isFirst is false:
|
||||||
mutable uint32 vertexBufferDirtyMask{}; // mask of vertex buffer indices which have been modified since last draw execute. It's the responsibility of the backend to unset bits
|
mutable uint32 vertexBufferDirtyMask{}; // mask of vertex buffer indices which have been modified since last draw execute
|
||||||
mutable uint32 vsUniformBufferDirtyMask{}; // mask of uniform buffer indices which have been modified (changed address or size) since last draw execute. It's the responsibility of the backend to unset bits
|
uint32 vsUniformBufferDirtyMask{}; // mask of uniform buffer indices which have been modified (changed address or size) since last draw execute
|
||||||
mutable uint32 psUniformBufferDirtyMask{};
|
uint32 psUniformBufferDirtyMask{};
|
||||||
mutable uint32 gsUniformBufferDirtyMask{};
|
uint32 gsUniformBufferDirtyMask{};
|
||||||
mutable bool aluConstVSDirty{};
|
bool aluConstVSDirty{};
|
||||||
mutable bool aluConstPSDirty{};
|
bool aluConstPSDirty{};
|
||||||
};
|
};
|
||||||
|
|
||||||
// texture
|
// texture
|
||||||
@ -168,10 +168,8 @@ void LatteCP_ProcessRingbuffer();
|
|||||||
|
|
||||||
// buffer cache
|
// buffer cache
|
||||||
|
|
||||||
bool LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount);
|
void LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, uint32 attribBufferDirtyMask, uint32 vsUniformBufferDirtyMask, uint32 psUniformBufferDirtyMask, uint32 gsUniformBufferDirtyMask, uint8& stageUniformModifiedMask, bool isIncremental = false);
|
||||||
void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, const LatteDrawcallContext& drawcallContext, uint8& stageUniformModifiedMask);
|
bool LatteBufferCache_LoadRemappedUniforms(struct LatteDecompilerShader* shader, float* uniformData, bool aluConstDirty, uint32 uniformBufferDirtyMask);
|
||||||
void LatteBufferCache_LoadRemappedUniforms(struct LatteDecompilerShader* shader, float* uniformData);
|
|
||||||
bool LatteBufferCache_LoadRemappedUniformsIncremental(LatteDecompilerShader* shader, float* uniformData, const LatteDrawcallContext& drawcallContext);
|
|
||||||
|
|
||||||
void LatteRenderTarget_updateViewport();
|
void LatteRenderTarget_updateViewport();
|
||||||
|
|
||||||
|
|||||||
@ -70,101 +70,32 @@ void rectGenerate4thVertex(uint32be* output, uint32be* input0, uint32be* input1,
|
|||||||
output[f] = _swapEndianU32(output[f]);
|
output[f] = _swapEndianU32(output[f]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LatteBufferCache_LoadRemappedUniforms(LatteDecompilerShader* shader, float* uniformData)
|
bool LatteBufferCache_LoadRemappedUniforms(LatteDecompilerShader* shader, float* uniformData, bool aluConstDirty, uint32 uniformBufferDirtyMask)
|
||||||
{
|
|
||||||
uint32 shaderAluConst;
|
|
||||||
uint32 shaderUniformRegisterOffset;
|
|
||||||
|
|
||||||
switch (shader->shaderType)
|
|
||||||
{
|
|
||||||
case LatteConst::ShaderType::Vertex:
|
|
||||||
shaderAluConst = 0x400;
|
|
||||||
shaderUniformRegisterOffset = mmSQ_VTX_UNIFORM_BLOCK_START;
|
|
||||||
break;
|
|
||||||
case LatteConst::ShaderType::Pixel:
|
|
||||||
shaderAluConst = 0;
|
|
||||||
shaderUniformRegisterOffset = mmSQ_PS_UNIFORM_BLOCK_START;
|
|
||||||
break;
|
|
||||||
case LatteConst::ShaderType::Geometry:
|
|
||||||
shaderAluConst = 0; // geometry shader has no ALU const
|
|
||||||
shaderUniformRegisterOffset = mmSQ_GS_UNIFORM_BLOCK_START;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
UNREACHABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sourced from uniform registers
|
|
||||||
uint32* aluConstBase = LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst;
|
|
||||||
for (auto it : shader->list_remappedUniformEntries_register)
|
|
||||||
{
|
|
||||||
uint64* uniformRegData = (uint64*)(aluConstBase + it.indexOffset / 4);
|
|
||||||
uint64* regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset);
|
|
||||||
regDest[0] = uniformRegData[0];
|
|
||||||
regDest[1] = uniformRegData[1];
|
|
||||||
}
|
|
||||||
// sourced from uniform buffers
|
|
||||||
for (auto& bufferGroup : shader->list_remappedUniformEntries_bufferGroups)
|
|
||||||
{
|
|
||||||
MPTR physicalAddr = LatteGPUState.contextRegister[shaderUniformRegisterOffset + bufferGroup.kcacheBankIdOffset / 4];
|
|
||||||
if (physicalAddr)
|
|
||||||
{
|
|
||||||
uint8* __restrict uniformBase = memory_base + physicalAddr;
|
|
||||||
for (auto& it : bufferGroup.entries)
|
|
||||||
{
|
|
||||||
uint64* __restrict regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset);
|
|
||||||
uint64* __restrict uniformEntrySrc = (uint64*)(uniformBase + it.indexOffset);
|
|
||||||
memcpy(regDest, uniformEntrySrc, 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (auto& it : bufferGroup.entries)
|
|
||||||
{
|
|
||||||
uint64* regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset);
|
|
||||||
regDest[0] = 0;
|
|
||||||
regDest[1] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// like LatteBufferCache_LoadRemappedUniforms but only updates data that is flagged as dirty in drawcallContext, returns true if any uniform value was updated.
|
|
||||||
bool LatteBufferCache_LoadRemappedUniformsIncremental(LatteDecompilerShader* shader, float* uniformData, const LatteDrawcallContext& drawcallContext)
|
|
||||||
{
|
{
|
||||||
bool hasChange = false;
|
bool hasChange = false;
|
||||||
uint32 shaderAluConst;
|
uint32 shaderAluConst;
|
||||||
uint32 shaderUniformRegisterOffset;
|
uint32 shaderUniformRegisterOffset;
|
||||||
|
|
||||||
bool hasDirtyAluConst = false;
|
|
||||||
uint32 uniformBufferDirtyMask = 0;
|
|
||||||
switch (shader->shaderType)
|
switch (shader->shaderType)
|
||||||
{
|
{
|
||||||
case LatteConst::ShaderType::Vertex:
|
case LatteConst::ShaderType::Vertex:
|
||||||
shaderAluConst = 0x400;
|
shaderAluConst = 0x400;
|
||||||
shaderUniformRegisterOffset = mmSQ_VTX_UNIFORM_BLOCK_START;
|
shaderUniformRegisterOffset = mmSQ_VTX_UNIFORM_BLOCK_START;
|
||||||
hasDirtyAluConst = drawcallContext.aluConstVSDirty;
|
|
||||||
uniformBufferDirtyMask = drawcallContext.vsUniformBufferDirtyMask;
|
|
||||||
drawcallContext.vsUniformBufferDirtyMask = 0;
|
|
||||||
break;
|
break;
|
||||||
case LatteConst::ShaderType::Pixel:
|
case LatteConst::ShaderType::Pixel:
|
||||||
shaderAluConst = 0;
|
shaderAluConst = 0;
|
||||||
shaderUniformRegisterOffset = mmSQ_PS_UNIFORM_BLOCK_START;
|
shaderUniformRegisterOffset = mmSQ_PS_UNIFORM_BLOCK_START;
|
||||||
hasDirtyAluConst = drawcallContext.aluConstPSDirty;
|
|
||||||
uniformBufferDirtyMask = drawcallContext.psUniformBufferDirtyMask;
|
|
||||||
drawcallContext.psUniformBufferDirtyMask = 0;
|
|
||||||
break;
|
break;
|
||||||
case LatteConst::ShaderType::Geometry:
|
case LatteConst::ShaderType::Geometry:
|
||||||
shaderAluConst = 0; // geometry shader has no ALU const
|
shaderAluConst = 0; // geometry shader has no ALU const
|
||||||
shaderUniformRegisterOffset = mmSQ_GS_UNIFORM_BLOCK_START;
|
shaderUniformRegisterOffset = mmSQ_GS_UNIFORM_BLOCK_START;
|
||||||
uniformBufferDirtyMask = drawcallContext.gsUniformBufferDirtyMask;
|
|
||||||
drawcallContext.gsUniformBufferDirtyMask = 0;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sourced from uniform registers
|
// sourced from uniform registers
|
||||||
if (hasDirtyAluConst)
|
if (aluConstDirty)
|
||||||
{
|
{
|
||||||
uint32* aluConstBase = LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst;
|
uint32* aluConstBase = LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst;
|
||||||
for (auto it : shader->list_remappedUniformEntries_register)
|
for (auto it : shader->list_remappedUniformEntries_register)
|
||||||
@ -238,100 +169,34 @@ bool LatteBufferCache_syncGPUUniformBuffers(LatteDecompilerShader* shader, const
|
|||||||
static sint32 s_vtxStateMaxIndex{};
|
static sint32 s_vtxStateMaxIndex{};
|
||||||
static sint32 s_vtxStateMaxInstance{};
|
static sint32 s_vtxStateMaxInstance{};
|
||||||
|
|
||||||
// upload vertex and uniform buffers
|
void LatteBufferCache_ProcessQueues()
|
||||||
bool LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount)
|
|
||||||
{
|
{
|
||||||
static uint32 s_syncBufferCounter = 0;
|
static uint32 s_syncBufferCounter = 0;
|
||||||
s_vtxStateMaxIndex = maxIndex;
|
|
||||||
s_vtxStateMaxInstance = baseInstance + instanceCount - 1;
|
|
||||||
|
|
||||||
s_syncBufferCounter++;
|
s_syncBufferCounter++;
|
||||||
if (s_syncBufferCounter >= 20)
|
if (s_syncBufferCounter >= 25)
|
||||||
{
|
{
|
||||||
LatteBufferCache_incrementalCleanup();
|
LatteBufferCache_incrementalCleanup();
|
||||||
s_syncBufferCounter = 0;
|
s_syncBufferCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LatteBufferCache_processDCFlushQueue();
|
LatteBufferCache_processDCFlushQueue();
|
||||||
// process queued deallocations from previous drawcall
|
// process queued deallocations from previous drawcall
|
||||||
LatteBufferCache_processDeallocations();
|
LatteBufferCache_processDeallocations();
|
||||||
|
|
||||||
// sync and bind vertex buffers
|
|
||||||
LatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader();
|
|
||||||
if (!parsedFetchShader)
|
|
||||||
return false;
|
|
||||||
uint32* __restrict bufferRegStartPtr = LatteGPUState.contextRegister + mmSQ_VTX_ATTRIBUTE_BLOCK_START;
|
|
||||||
for (auto& bufferGroup : parsedFetchShader->bufferGroups)
|
|
||||||
{
|
|
||||||
uint32 bufferIndex = bufferGroup.attributeBufferIndex;
|
|
||||||
uint32* __restrict bufferRegs = bufferRegStartPtr + bufferIndex * 7;
|
|
||||||
MPTR bufferAddress = bufferRegs[0];
|
|
||||||
/* uint32 bufferSize = bufferRegs[1] + 1; */
|
|
||||||
uint32 bufferStride = (bufferRegs[2] >> 11) & 0xFFFF;
|
|
||||||
|
|
||||||
if (bufferAddress == MPTR_NULL) [[unlikely]]
|
|
||||||
{
|
|
||||||
g_renderer->buffer_bindVertexBuffer(bufferIndex, 0, 0);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dont rely on buffer size given by game
|
// upload vertex and uniform buffers and update bindings
|
||||||
uint32 fixedBufferSize = 0;
|
void LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, uint32 attribBufferDirtyMask, uint32 vsUniformBufferDirtyMask, uint32 psUniformBufferDirtyMask, uint32 gsUniformBufferDirtyMask, uint8& stageUniformModifiedMask, bool isIncremental)
|
||||||
if (bufferGroup.hasVtxIndexAccess)
|
|
||||||
fixedBufferSize = bufferStride * (maxIndex + 1) + bufferGroup.maxOffset;
|
|
||||||
if (bufferGroup.hasInstanceIndexAccess)
|
|
||||||
{
|
{
|
||||||
uint32 fixedBufferSizeInstance = bufferStride * ((baseInstance + instanceCount) + 1) + bufferGroup.maxOffset;
|
|
||||||
fixedBufferSize = std::max(fixedBufferSize, fixedBufferSizeInstance);
|
|
||||||
}
|
|
||||||
if (fixedBufferSize == 0 || bufferStride == 0)
|
|
||||||
fixedBufferSize += 128;
|
|
||||||
|
|
||||||
|
|
||||||
#if BOOST_OS_MACOS && defined(ENABLE_VULKAN)
|
|
||||||
if(bufferStride % 4 != 0)
|
|
||||||
{
|
|
||||||
if (g_renderer->GetType() == RendererAPI::Vulkan)
|
|
||||||
{
|
|
||||||
if (VulkanRenderer* vkRenderer = VulkanRenderer::GetInstance())
|
|
||||||
{
|
|
||||||
auto fixedBuffer = vkRenderer->buffer_genStrideWorkaroundVertexBuffer(bufferAddress, fixedBufferSize, bufferStride);
|
|
||||||
vkRenderer->buffer_bindVertexStrideWorkaroundBuffer(fixedBuffer.first, fixedBuffer.second, bufferIndex, fixedBufferSize);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32 bindOffset = LatteBufferCache_retrieveDataInCache(bufferAddress, fixedBufferSize);
|
|
||||||
g_renderer->buffer_bindVertexBuffer(bufferIndex, bindOffset, fixedBufferSize);
|
|
||||||
}
|
|
||||||
// sync uniform buffers
|
|
||||||
LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();
|
|
||||||
LatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();
|
|
||||||
LatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();
|
|
||||||
if (vertexShader && vertexShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
|
||||||
LatteBufferCache_syncGPUUniformBuffers(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex, 0xFFFFFFFF);
|
|
||||||
if (pixelShader && pixelShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
|
||||||
LatteBufferCache_syncGPUUniformBuffers(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel, 0xFFFFFFFF);
|
|
||||||
if (geometryShader && geometryShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
|
||||||
LatteBufferCache_syncGPUUniformBuffers(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry, 0xFFFFFFFF);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// similar to LatteBufferCache_SyncIncremental but updates only the bindings that are marked in the dirty masks
|
|
||||||
void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, const LatteDrawcallContext& drawcallContext, uint8& stageUniformModifiedMask)
|
|
||||||
{
|
|
||||||
// uint32 attribBufferDirtyMask, uint32 uniformBufferVSDirtyMask, uint32 uniformBufferPSDirtyMask, uint32 uniformBufferGSDirtyMask
|
|
||||||
LatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader();
|
LatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader();
|
||||||
cemu_assert_debug(parsedFetchShader);
|
cemu_assert_debug(parsedFetchShader);
|
||||||
uint32 attribBufferDirtyMask = drawcallContext.vertexBufferDirtyMask;
|
|
||||||
|
|
||||||
|
// todo - vertex attribute offsets may eventually be allowed to change between incremental draws, we should set the attrib dirty bits in that case
|
||||||
|
if (isIncremental)
|
||||||
|
{
|
||||||
|
// dont process flush queue and dont process deallocations yet, we are in the middle of a sequence of drawcalls that (most likely) reuse previous bindings
|
||||||
if ( maxIndex > s_vtxStateMaxIndex )
|
if ( maxIndex > s_vtxStateMaxIndex )
|
||||||
{
|
{
|
||||||
attribBufferDirtyMask = 0xFFFFFFFF;
|
attribBufferDirtyMask = 0xFFFFFFFF;
|
||||||
// todo - if the fetch shader can change between incremental calls, then we should also mark all of drawcallContext.vertexBufferDirtyMask as dirty. Or we could track the count per-buffer instead of as max index and max instance
|
|
||||||
// but for simplicity sake we should disallow fetch shader changes that use a differing set of buffers (this is already the case)
|
|
||||||
s_vtxStateMaxIndex = maxIndex;
|
s_vtxStateMaxIndex = maxIndex;
|
||||||
}
|
}
|
||||||
uint32 maxInstance = baseInstance + instanceCount - 1;
|
uint32 maxInstance = baseInstance + instanceCount - 1;
|
||||||
@ -340,10 +205,16 @@ void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 b
|
|||||||
attribBufferDirtyMask = 0xFFFFFFFF;
|
attribBufferDirtyMask = 0xFFFFFFFF;
|
||||||
s_vtxStateMaxInstance = maxInstance;
|
s_vtxStateMaxInstance = maxInstance;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LatteBufferCache_ProcessQueues();
|
||||||
|
s_vtxStateMaxIndex = maxIndex;
|
||||||
|
uint32 maxInstance = baseInstance + instanceCount - 1;
|
||||||
|
s_vtxStateMaxInstance = maxInstance;
|
||||||
|
}
|
||||||
attribBufferDirtyMask &= parsedFetchShader->attributeBufferMask;
|
attribBufferDirtyMask &= parsedFetchShader->attributeBufferMask;
|
||||||
|
|
||||||
// dont process flush queue and dont process deallocations yet, we are in the middle of a sequence of drawcalls that (most likely) reuse previous bindings
|
|
||||||
|
|
||||||
// sync and bind dirty vertex buffers
|
// sync and bind dirty vertex buffers
|
||||||
if (attribBufferDirtyMask != 0)
|
if (attribBufferDirtyMask != 0)
|
||||||
{
|
{
|
||||||
@ -353,7 +224,6 @@ void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 b
|
|||||||
uint32 bufferIndex = bufferGroup.attributeBufferIndex;
|
uint32 bufferIndex = bufferGroup.attributeBufferIndex;
|
||||||
if ((attribBufferDirtyMask&(1<<bufferIndex)) == 0)
|
if ((attribBufferDirtyMask&(1<<bufferIndex)) == 0)
|
||||||
continue;
|
continue;
|
||||||
drawcallContext.vertexBufferDirtyMask &= ~(1<<bufferIndex);
|
|
||||||
uint32* __restrict bufferRegs = bufferRegStartPtr + bufferIndex * 7;
|
uint32* __restrict bufferRegs = bufferRegStartPtr + bufferIndex * 7;
|
||||||
MPTR bufferAddress = bufferRegs[0];
|
MPTR bufferAddress = bufferRegs[0];
|
||||||
uint32 bufferStride = (bufferRegs[2] >> 11) & 0xFFFF;
|
uint32 bufferStride = (bufferRegs[2] >> 11) & 0xFFFF;
|
||||||
@ -403,17 +273,17 @@ void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 b
|
|||||||
// todo - if we AND the shader uniform buffer mask and the dirty mask we can completely skip calling syncGPUUniformBuffers if no relevant buffer was updated
|
// todo - if we AND the shader uniform buffer mask and the dirty mask we can completely skip calling syncGPUUniformBuffers if no relevant buffer was updated
|
||||||
if (vertexShader && vertexShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
if (vertexShader && vertexShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
||||||
{
|
{
|
||||||
if (LatteBufferCache_syncGPUUniformBuffers(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex, drawcallContext.vsUniformBufferDirtyMask))
|
if (LatteBufferCache_syncGPUUniformBuffers(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex, vsUniformBufferDirtyMask))
|
||||||
stageUniformModifiedMask |= (1<<VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX);
|
stageUniformModifiedMask |= (1<<VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX);
|
||||||
}
|
}
|
||||||
if (pixelShader && pixelShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
if (pixelShader && pixelShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
||||||
{
|
{
|
||||||
if (LatteBufferCache_syncGPUUniformBuffers(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel, drawcallContext.psUniformBufferDirtyMask))
|
if (LatteBufferCache_syncGPUUniformBuffers(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel, psUniformBufferDirtyMask))
|
||||||
stageUniformModifiedMask |= (1<<VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT); // todo - move this enum to Latte?
|
stageUniformModifiedMask |= (1<<VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT); // todo - move this enum to Latte?
|
||||||
}
|
}
|
||||||
if (geometryShader && geometryShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
if (geometryShader && geometryShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
|
||||||
{
|
{
|
||||||
if ( LatteBufferCache_syncGPUUniformBuffers(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry, drawcallContext.gsUniformBufferDirtyMask) )
|
if ( LatteBufferCache_syncGPUUniformBuffers(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry, gsUniformBufferDirtyMask) )
|
||||||
stageUniformModifiedMask |= (1<<VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY);
|
stageUniformModifiedMask |= (1<<VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,6 +84,11 @@ public:
|
|||||||
performanceMonitor.cycle[performanceMonitor.cycleIndex].fastDrawCallCounter++;
|
performanceMonitor.cycle[performanceMonitor.cycleIndex].fastDrawCallCounter++;
|
||||||
m_drawcallContext.isFirst = false;
|
m_drawcallContext.isFirst = false;
|
||||||
m_drawcallContext.vertexBufferDirtyMask = 0;
|
m_drawcallContext.vertexBufferDirtyMask = 0;
|
||||||
|
m_drawcallContext.vsUniformBufferDirtyMask = 0;
|
||||||
|
m_drawcallContext.psUniformBufferDirtyMask = 0;
|
||||||
|
m_drawcallContext.gsUniformBufferDirtyMask = 0;
|
||||||
|
m_drawcallContext.aluConstVSDirty = false;
|
||||||
|
m_drawcallContext.aluConstPSDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void endDrawPass()
|
void endDrawPass()
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
#define LATTE_NUM_COLOR_TARGET 8
|
#define LATTE_NUM_COLOR_TARGET 8
|
||||||
|
|
||||||
#define LATTE_NUM_MAX_TEX_UNITS 18 // number of available texture units per shader stage (this might be higher than 18? BotW is the only game which uses more than 16?)
|
#define LATTE_NUM_MAX_TEX_UNITS 18 // number of available texture units per shader stage (this might be higher than 18? BotW is the only game which uses more than 16?)
|
||||||
#define LATTE_NUM_MAX_UNIFORM_BUFFERS 16 // number of supported uniform buffer binding locations
|
#define LATTE_NUM_MAX_UNIFORM_BUFFERS 16 // number of supported uniform buffer binding locations per shader stage
|
||||||
|
|
||||||
#define LATTE_VS_ATTRIBUTE_LIMIT 32 // todo: verify
|
#define LATTE_VS_ATTRIBUTE_LIMIT 32 // todo: verify
|
||||||
#define LATTE_NUM_MAX_ATTRIBUTE_LOCATIONS 256 // should this be 128 since there are only 128 GPRs?
|
#define LATTE_NUM_MAX_ATTRIBUTE_LOCATIONS 256 // should this be 128 since there are only 128 GPRs?
|
||||||
|
|||||||
@ -1164,7 +1164,8 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
|||||||
{
|
{
|
||||||
// synchronize vertex and uniform cache and update buffer bindings
|
// synchronize vertex and uniform cache and update buffer bindings
|
||||||
// We need to call this before getting the render command encoder, since it can cause buffer copies
|
// We need to call this before getting the render command encoder, since it can cause buffer copies
|
||||||
LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount);
|
uint8 stageUniformModifiedMask = 0;
|
||||||
|
LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render pass
|
// Render pass
|
||||||
@ -2138,7 +2139,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
|
|||||||
}
|
}
|
||||||
if (shader->uniform.loc_remapped >= 0)
|
if (shader->uniform.loc_remapped >= 0)
|
||||||
{
|
{
|
||||||
LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped));
|
LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped), true, (1<<LATTE_NUM_MAX_UNIFORM_BUFFERS)-1);
|
||||||
}
|
}
|
||||||
if (shader->uniform.loc_uniformRegister >= 0)
|
if (shader->uniform.loc_uniformRegister >= 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -975,7 +975,8 @@ void OpenGLRenderer::draw_genericDrawHandler(uint32 baseVertex, uint32 baseInsta
|
|||||||
endPerfMonProfiling(performanceMonitor.gpuTime_dcStageIndexMgr);
|
endPerfMonProfiling(performanceMonitor.gpuTime_dcStageIndexMgr);
|
||||||
|
|
||||||
// synchronize vertex and uniform buffers
|
// synchronize vertex and uniform buffers
|
||||||
LatteBufferCache_Sync(indexState.minIndex + baseVertex, indexState.maxIndex + baseVertex, baseInstance, instanceCount);
|
uint8 stageUniformModifiedMask = 0;
|
||||||
|
LatteBufferCache_Sync(indexState.minIndex + baseVertex, indexState.maxIndex + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask);
|
||||||
|
|
||||||
_setupVertexAttributes();
|
_setupVertexAttributes();
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ void OpenGLRenderer::uniformData_update()
|
|||||||
auto& list_uniformMapping = shader->list_remappedUniformEntries;
|
auto& list_uniformMapping = shader->list_remappedUniformEntries;
|
||||||
cemu_assert_debug(list_uniformMapping.size() <= 256);
|
cemu_assert_debug(list_uniformMapping.size() <= 256);
|
||||||
sint32 remappedArraySize = (sint32)list_uniformMapping.size();
|
sint32 remappedArraySize = (sint32)list_uniformMapping.size();
|
||||||
LatteBufferCache_LoadRemappedUniforms(shader, (float*)(_gl_remappedUniformData));
|
LatteBufferCache_LoadRemappedUniforms(shader, (float*)(_gl_remappedUniformData), true, (1<<LATTE_NUM_MAX_UNIFORM_BUFFERS)-1);
|
||||||
// update values only when the hash changed
|
// update values only when the hash changed
|
||||||
if (remappedArraySize > 0)
|
if (remappedArraySize > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -563,7 +563,7 @@ private:
|
|||||||
// uniform
|
// uniform
|
||||||
uint32 uniformData_uploadUniformDataBufferGetOffset(std::span<uint8, std::dynamic_extent> data);
|
uint32 uniformData_uploadUniformDataBufferGetOffset(std::span<uint8, std::dynamic_extent> data);
|
||||||
void uniformData_updateUniformVars(uint32 shaderStageIndex, LatteDecompilerShader* shader, float* __restrict uniformBuf);
|
void uniformData_updateUniformVars(uint32 shaderStageIndex, LatteDecompilerShader* shader, float* __restrict uniformBuf);
|
||||||
void uniformData_updateUniformVarsIncremental(uint32 shaderStageIndex, LatteDecompilerShader* shader, const LatteDrawcallContext& drawcallContext, uint8& stageUniformModifiedMask, float* __restrict uniformBuf);
|
void uniformData_updateUniformVarsIncremental(uint32 shaderStageIndex, LatteDecompilerShader* shader, uint8& stageUniformModifiedMask, float* __restrict uniformBuf, bool aluConstDirty, uint32 uniformBufferDirtyMask);
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
void CreatePipelineCache();
|
void CreatePipelineCache();
|
||||||
|
|||||||
@ -405,7 +405,7 @@ void VulkanRenderer::uniformData_updateUniformVars(uint32 shaderStageIndex, Latt
|
|||||||
}
|
}
|
||||||
if (shader->uniform.loc_remapped >= 0)
|
if (shader->uniform.loc_remapped >= 0)
|
||||||
{
|
{
|
||||||
LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped));
|
LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped), true, (1<<LATTE_NUM_MAX_UNIFORM_BUFFERS)-1);
|
||||||
}
|
}
|
||||||
if (shader->uniform.loc_uniformRegister >= 0)
|
if (shader->uniform.loc_uniformRegister >= 0)
|
||||||
{
|
{
|
||||||
@ -454,7 +454,7 @@ void VulkanRenderer::uniformData_updateUniformVars(uint32 shaderStageIndex, Latt
|
|||||||
dynamicOffsetInfo.uniformVarBufferOffset[shaderStageIndex] = uniformData_uploadUniformDataBufferGetOffset({(uint8*)uniformBuf, shader->uniform.uniformRangeSize});
|
dynamicOffsetInfo.uniformVarBufferOffset[shaderStageIndex] = uniformData_uploadUniformDataBufferGetOffset({(uint8*)uniformBuf, shader->uniform.uniformRangeSize});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::uniformData_updateUniformVarsIncremental(uint32 shaderStageIndex, LatteDecompilerShader* shader, const LatteDrawcallContext& drawcallContext, uint8& stageUniformModifiedMask, float* __restrict uniformBuf)
|
void VulkanRenderer::uniformData_updateUniformVarsIncremental(uint32 shaderStageIndex, LatteDecompilerShader* shader, uint8& stageUniformModifiedMask, float* __restrict uniformBuf, bool aluConstDirty, uint32 uniformBufferDirtyMask)
|
||||||
{
|
{
|
||||||
// similar to uniformData_updateUniformVars, but checks only the fields that can change during a fast draw sequence
|
// similar to uniformData_updateUniformVars, but checks only the fields that can change during a fast draw sequence
|
||||||
auto GET_UNIFORM_DATA_PTR = [&uniformBuf](size_t index) { return uniformBuf + (index / 4); };
|
auto GET_UNIFORM_DATA_PTR = [&uniformBuf](size_t index) { return uniformBuf + (index / 4); };
|
||||||
@ -470,22 +470,19 @@ void VulkanRenderer::uniformData_updateUniformVarsIncremental(uint32 shaderStage
|
|||||||
if (shader->uniform.loc_remapped >= 0)
|
if (shader->uniform.loc_remapped >= 0)
|
||||||
{
|
{
|
||||||
cemu_assert_debug(shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED);
|
cemu_assert_debug(shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED);
|
||||||
hasChange = LatteBufferCache_LoadRemappedUniformsIncremental(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped), drawcallContext);
|
hasChange = LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped), aluConstDirty, uniformBufferDirtyMask);
|
||||||
}
|
}
|
||||||
if (shader->uniform.loc_uniformRegister >= 0)
|
if (shader->uniform.loc_uniformRegister >= 0 && aluConstDirty)
|
||||||
{
|
{
|
||||||
cemu_assert_debug(shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE);
|
cemu_assert_debug(shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE);
|
||||||
bool isDirty = false;
|
|
||||||
sint32 shaderAluConst;
|
sint32 shaderAluConst;
|
||||||
switch (shader->shaderType)
|
switch (shader->shaderType)
|
||||||
{
|
{
|
||||||
case LatteConst::ShaderType::Vertex:
|
case LatteConst::ShaderType::Vertex:
|
||||||
shaderAluConst = 0x400;
|
shaderAluConst = 0x400;
|
||||||
isDirty = drawcallContext.aluConstVSDirty;
|
|
||||||
break;
|
break;
|
||||||
case LatteConst::ShaderType::Pixel:
|
case LatteConst::ShaderType::Pixel:
|
||||||
shaderAluConst = 0;
|
shaderAluConst = 0;
|
||||||
isDirty = drawcallContext.aluConstPSDirty;
|
|
||||||
break;
|
break;
|
||||||
case LatteConst::ShaderType::Geometry:
|
case LatteConst::ShaderType::Geometry:
|
||||||
cemu_assert_suspicious();
|
cemu_assert_suspicious();
|
||||||
@ -495,13 +492,10 @@ void VulkanRenderer::uniformData_updateUniformVarsIncremental(uint32 shaderStage
|
|||||||
default:
|
default:
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
}
|
}
|
||||||
if (isDirty)
|
|
||||||
{
|
|
||||||
hasChange = true;
|
hasChange = true;
|
||||||
uint32* uniformRegData = (uint32*)(LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst);
|
uint32* uniformRegData = (uint32*)(LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst);
|
||||||
memcpy(GET_UNIFORM_DATA_PTR(shader->uniform.loc_uniformRegister), uniformRegData, shader->uniform.count_uniformRegister * 16);
|
memcpy(GET_UNIFORM_DATA_PTR(shader->uniform.loc_uniformRegister), uniformRegData, shader->uniform.count_uniformRegister * 16);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (hasChange)
|
if (hasChange)
|
||||||
{
|
{
|
||||||
dynamicOffsetInfo.uniformVarBufferOffset[shaderStageIndex] = uniformData_uploadUniformDataBufferGetOffset({(uint8*)uniformBuf, shader->uniform.uniformRangeSize});
|
dynamicOffsetInfo.uniformVarBufferOffset[shaderStageIndex] = uniformData_uploadUniformDataBufferGetOffset({(uint8*)uniformBuf, shader->uniform.uniformRangeSize});
|
||||||
@ -1417,7 +1411,8 @@ void VulkanRenderer::draw_execute_first(uint32 baseVertex, uint32 baseInstance,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// synchronize vertex and uniform cache and update buffer bindings
|
// synchronize vertex and uniform cache and update buffer bindings
|
||||||
LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount);
|
uint8 stageUniformModifiedMask = 0;
|
||||||
|
LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
PipelineInfo* pipeline_info = draw_getOrCreateGraphicsPipeline(count);
|
PipelineInfo* pipeline_info = draw_getOrCreateGraphicsPipeline(count);
|
||||||
@ -1529,13 +1524,11 @@ void VulkanRenderer::draw_execute_continued(uint32 baseVertex, uint32 baseInstan
|
|||||||
|
|
||||||
uint8 stageUniformModifiedMask = 0; // one bit for each stage (using SHADER_STAGE_INDEX_* as bit index). Set if any uniform data has been modified and needs to be reuploaded
|
uint8 stageUniformModifiedMask = 0; // one bit for each stage (using SHADER_STAGE_INDEX_* as bit index). Set if any uniform data has been modified and needs to be reuploaded
|
||||||
if (vertexShader)
|
if (vertexShader)
|
||||||
uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, vertexShader, drawcallContext, stageUniformModifiedMask, s_vkUniformDataVS);
|
uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, vertexShader, stageUniformModifiedMask, s_vkUniformDataVS, drawcallContext.aluConstVSDirty, drawcallContext.vsUniformBufferDirtyMask);
|
||||||
if (pixelShader)
|
if (pixelShader)
|
||||||
uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, pixelShader, drawcallContext, stageUniformModifiedMask, s_vkUniformDataPS);
|
uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, pixelShader, stageUniformModifiedMask, s_vkUniformDataPS, drawcallContext.aluConstPSDirty, drawcallContext.psUniformBufferDirtyMask);
|
||||||
if (geometryShader)
|
if (geometryShader)
|
||||||
uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY, geometryShader, drawcallContext, stageUniformModifiedMask, s_vkUniformDataGS);
|
uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY, geometryShader, stageUniformModifiedMask, s_vkUniformDataGS, false, drawcallContext.gsUniformBufferDirtyMask);
|
||||||
drawcallContext.aluConstVSDirty = false;
|
|
||||||
drawcallContext.aluConstPSDirty = false;
|
|
||||||
// store where the read pointer should go after command buffer execution
|
// store where the read pointer should go after command buffer execution
|
||||||
m_cmdBufferUniformRingbufIndices[m_commandBufferIndex] = m_uniformVarBufferWriteIndex;
|
m_cmdBufferUniformRingbufIndices[m_commandBufferIndex] = m_uniformVarBufferWriteIndex;
|
||||||
|
|
||||||
@ -1587,7 +1580,7 @@ void VulkanRenderer::draw_execute_continued(uint32 baseVertex, uint32 baseInstan
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// synchronize vertex and uniform cache and update buffer bindings
|
// synchronize vertex and uniform cache and update buffer bindings
|
||||||
LatteBufferCache_SyncIncremental(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, drawcallContext, stageUniformModifiedMask);
|
LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, drawcallContext.vertexBufferDirtyMask, drawcallContext.vsUniformBufferDirtyMask, drawcallContext.psUniformBufferDirtyMask, drawcallContext.gsUniformBufferDirtyMask, stageUniformModifiedMask, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_state.descriptorSetsChanged = false;
|
m_state.descriptorSetsChanged = false;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user