mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-09 17:14:47 -06:00
Vulkan: Smaller fixes + code cleanup
This commit is contained in:
parent
62ac48f0e9
commit
4c4ef50f49
@ -194,17 +194,23 @@ void LatteBufferCache_Sync(uint32 maxIndex, uint32 baseInstance, uint32 instance
|
|||||||
if (isIncremental)
|
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
|
// 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
|
||||||
|
uint32 maxInstance = baseInstance + instanceCount - 1;
|
||||||
|
bool hasBufferChange = attribBufferDirtyMask != 0;
|
||||||
if ( maxIndex > s_vtxStateMaxIndex )
|
if ( maxIndex > s_vtxStateMaxIndex )
|
||||||
{
|
{
|
||||||
attribBufferDirtyMask = 0xFFFFFFFF;
|
attribBufferDirtyMask = 0xFFFFFFFF;
|
||||||
s_vtxStateMaxIndex = maxIndex;
|
s_vtxStateMaxIndex = maxIndex;
|
||||||
}
|
}
|
||||||
uint32 maxInstance = baseInstance + instanceCount - 1;
|
|
||||||
if ( maxInstance > s_vtxStateMaxInstance )
|
if ( maxInstance > s_vtxStateMaxInstance )
|
||||||
{
|
{
|
||||||
attribBufferDirtyMask = 0xFFFFFFFF;
|
attribBufferDirtyMask = 0xFFFFFFFF;
|
||||||
s_vtxStateMaxInstance = maxInstance;
|
s_vtxStateMaxInstance = maxInstance;
|
||||||
}
|
}
|
||||||
|
if (hasBufferChange)
|
||||||
|
{
|
||||||
|
s_vtxStateMaxIndex = maxIndex;
|
||||||
|
s_vtxStateMaxInstance = maxInstance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1021,7 +1021,6 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
|
|||||||
LatteCMDPtr cmd, cmdStart, cmdEnd;
|
LatteCMDPtr cmd, cmdStart, cmdEnd;
|
||||||
if (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd))
|
if (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd))
|
||||||
{
|
{
|
||||||
// cemuLog_log(LogType::Force, "[FastDrawMode] End due running out of commands");
|
|
||||||
drawPassCtx.endDrawPass();
|
drawPassCtx.endDrawPass();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1049,7 +1048,6 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
|
|||||||
(registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)) ||
|
(registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)) ||
|
||||||
(registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)))
|
(registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)))
|
||||||
{
|
{
|
||||||
// cemuLog_log(LogType::Force, "[FastDrawMode] End due to texture change");
|
|
||||||
drawPassCtx.endDrawPass(); // texture updates end the current draw sequence
|
drawPassCtx.endDrawPass(); // texture updates end the current draw sequence
|
||||||
}
|
}
|
||||||
else if (registerStart >= mmSQ_VTX_ATTRIBUTE_BLOCK_START && registerEnd <= mmSQ_VTX_ATTRIBUTE_BLOCK_END)
|
else if (registerStart >= mmSQ_VTX_ATTRIBUTE_BLOCK_START && registerEnd <= mmSQ_VTX_ATTRIBUTE_BLOCK_END)
|
||||||
@ -1089,7 +1087,7 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
|
|||||||
drawPassCtx.MarkVSAluConstantsDirty();
|
drawPassCtx.MarkVSAluConstantsDirty();
|
||||||
else
|
else
|
||||||
drawPassCtx.MarkPSAluConstantsDirty();
|
drawPassCtx.MarkPSAluConstantsDirty();
|
||||||
// todo - we could further optimize by tracking the min/max range of modified ALU constants
|
// todo - we could further optimize by tracking the min/max range of modified ALU constants and only uploading the affected range. Possibly not worth it
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1120,11 +1118,7 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
|
|||||||
}
|
}
|
||||||
case IT_SET_CONTEXT_REG:
|
case IT_SET_CONTEXT_REG:
|
||||||
{
|
{
|
||||||
// LatteCP_itSetRegistersGeneric<LATTE_REG_BASE_CONTEXT>(cmd, nWords);
|
|
||||||
bool hasChanged = LatteCP_itSetRegistersGeneric2<LATTE_REG_BASE_CONTEXT>(cmdData, nWords, [](uint32 registerStart, uint32 registerEnd, bool regValuesChanged){});
|
bool hasChanged = LatteCP_itSetRegistersGeneric2<LATTE_REG_BASE_CONTEXT>(cmdData, nWords, [](uint32 registerStart, uint32 registerEnd, bool regValuesChanged){});
|
||||||
//cemuLog_log(LogType::Force, "[FastDrawMode] Potential end due to SetContextReg (itHeader {:08x} data {:08x}) -> HasChanged {}", itHeader, (uint32)cmdData[0], hasChanged);
|
|
||||||
// drawPassCtx.endDrawPass();
|
|
||||||
// drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);
|
|
||||||
if (hasChanged)
|
if (hasChanged)
|
||||||
{
|
{
|
||||||
drawPassCtx.endDrawPass();
|
drawPassCtx.endDrawPass();
|
||||||
@ -1144,10 +1138,8 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
|
|||||||
case IT_SET_SAMPLER:
|
case IT_SET_SAMPLER:
|
||||||
{
|
{
|
||||||
bool hasChanged = LatteCP_itSetRegistersGeneric2<LATTE_REG_BASE_SAMPLER>(cmdData, nWords, [](uint32 registerStart, uint32 registerEnd, bool regValuesChanged){});
|
bool hasChanged = LatteCP_itSetRegistersGeneric2<LATTE_REG_BASE_SAMPLER>(cmdData, nWords, [](uint32 registerStart, uint32 registerEnd, bool regValuesChanged){});
|
||||||
//cemuLog_log(LogType::Force, "[FastDrawMode] Set sampler (reg change = {} - filtered)", hasChanged);
|
|
||||||
if (hasChanged)
|
if (hasChanged)
|
||||||
{
|
{
|
||||||
//cemuLog_log(LogType::Force, "[FastDrawMode] End due to sampler change");
|
|
||||||
drawPassCtx.endDrawPass();
|
drawPassCtx.endDrawPass();
|
||||||
drawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);
|
drawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);
|
||||||
return;
|
return;
|
||||||
@ -1155,9 +1147,7 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// unsupported command for fast draw
|
// unallowed command for fast draw
|
||||||
//cemuLog_log(LogType::Force, "[FastDrawMode] Unallowed command. Data: {:08x} {:08x} {:08x} {:08x} {:08x} {:08x}", (uint32)itHeader, (uint32)cmdData[0], (uint32)cmdData[1], (uint32)cmdData[2], (uint32)cmdData[3], (uint32)cmdData[4], (uint32)cmdData[5]);
|
|
||||||
//cemuLog_log(LogType::Force, "[FastDrawMode] End due to unallowed packet 0x{:08x}", itHeader);
|
|
||||||
drawPassCtx.endDrawPass();
|
drawPassCtx.endDrawPass();
|
||||||
drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);
|
drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);
|
||||||
return;
|
return;
|
||||||
@ -1169,8 +1159,7 @@ void LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCt
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// unsupported command for fast draw
|
// unallowed command for fast draw
|
||||||
//cemuLog_log(LogType::Force, "[FastDrawMode] End due to uknown packet 0x{:08x}", itHeader);
|
|
||||||
drawPassCtx.endDrawPass();
|
drawPassCtx.endDrawPass();
|
||||||
drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);
|
drawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1062,7 +1062,7 @@ robin_hood::unordered_flat_map<uint64, ShaderStateInfo, ShaderStateDirectHash> s
|
|||||||
// folly::F14FastMap<uint64, ShaderStateInfo, FPHDirectHash>
|
// folly::F14FastMap<uint64, ShaderStateInfo, FPHDirectHash>
|
||||||
// robin_hood::unordered_flat_map ended up performing close to best and was choosen because we already have it included in the project anyway
|
// robin_hood::unordered_flat_map ended up performing close to best and was choosen because we already have it included in the project anyway
|
||||||
|
|
||||||
FORCEINLINE uint64 CalcCombinedAuxHash(LatteFetchShader* fetchShader, LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader)
|
FORCE_INLINE uint64 CalcCombinedAuxHash(LatteFetchShader* fetchShader, LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader)
|
||||||
{
|
{
|
||||||
uint64 vsAuxHash = vertexShader ? LatteSHRC_CalcVSAuxHash(vertexShader, LatteGPUState.contextRegister) : 0;
|
uint64 vsAuxHash = vertexShader ? LatteSHRC_CalcVSAuxHash(vertexShader, LatteGPUState.contextRegister) : 0;
|
||||||
uint64 psAuxHash = pixelShader ? LatteSHRC_CalcPSAuxHash(pixelShader, LatteGPUState.contextRegister) : 0;
|
uint64 psAuxHash = pixelShader ? LatteSHRC_CalcPSAuxHash(pixelShader, LatteGPUState.contextRegister) : 0;
|
||||||
|
|||||||
@ -1027,6 +1027,21 @@ void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteD
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// some existing graphic pack replacement shaders rely on uf_fragCoordScale despite the original shader not needing it. We handle these exceptions here
|
||||||
|
switch (shaderContext->shaderBaseHash)
|
||||||
|
{
|
||||||
|
case 0x21e6bc9b0cdbe8d7: case 0x37040a485a29d54e: case 0x37a4ec1a7dbc7391:
|
||||||
|
case 0x50e29e8929cea348: case 0x572a6cfa3943923d: case 0x59df1c7e1806366c:
|
||||||
|
case 0x6ea8b1aa69c0b6f7: case 0x88133ee405eaae28: case 0x95a5a89d62998e0d:
|
||||||
|
case 0x998a9f67e353657b: case 0x9f6adb9a651f84b9: case 0xa5e9d150276a805c:
|
||||||
|
case 0xa7f4801a8d29e333: case 0xbe99d80628d31127: case 0xc14019840473ff86:
|
||||||
|
case 0xc612390d4c70f430: case 0xcb0e6e8cbec4502a: case 0xe334517825fdd599:
|
||||||
|
case 0xe39a2a718bc419fe: case 0xfdf33c607cd1d737: case 0xff71dcd2ad4defdc:
|
||||||
|
shaderContext->analyzer.hasFragCoordAccess = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// analyze CF stack
|
// analyze CF stack
|
||||||
sint32 cfCurrentStackDepth = 0;
|
sint32 cfCurrentStackDepth = 0;
|
||||||
|
|||||||
@ -50,7 +50,7 @@ std::vector<MetalRenderer::DeviceInfo> MetalRenderer::GetDevices()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetalRenderer::MetalRenderer()
|
MetalRenderer::MetalRenderer() : Renderer(RendererAPI::Metal)
|
||||||
{
|
{
|
||||||
// Options
|
// Options
|
||||||
|
|
||||||
|
|||||||
@ -153,11 +153,6 @@ public:
|
|||||||
MetalRenderer();
|
MetalRenderer();
|
||||||
~MetalRenderer() override;
|
~MetalRenderer() override;
|
||||||
|
|
||||||
RendererAPI GetType() override
|
|
||||||
{
|
|
||||||
return RendererAPI::Metal;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MetalRenderer* GetInstance() {
|
static MetalRenderer* GetInstance() {
|
||||||
return static_cast<MetalRenderer*>(g_renderer.get());
|
return static_cast<MetalRenderer*>(g_renderer.get());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,7 +111,7 @@ static const GLenum glAlphaTestFunc[] =
|
|||||||
GL_ALWAYS
|
GL_ALWAYS
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenGLRenderer::OpenGLRenderer()
|
OpenGLRenderer::OpenGLRenderer() : Renderer(RendererAPI::OpenGL)
|
||||||
{
|
{
|
||||||
glRendererState.useTextureUploadBuffer = false;
|
glRendererState.useTextureUploadBuffer = false;
|
||||||
if (glRendererState.useTextureUploadBuffer)
|
if (glRendererState.useTextureUploadBuffer)
|
||||||
|
|||||||
@ -35,8 +35,6 @@ public:
|
|||||||
OpenGLRenderer();
|
OpenGLRenderer();
|
||||||
~OpenGLRenderer();
|
~OpenGLRenderer();
|
||||||
|
|
||||||
RendererAPI GetType() override { return RendererAPI::OpenGL; }
|
|
||||||
|
|
||||||
static OpenGLRenderer* GetInstance();
|
static OpenGLRenderer* GetInstance();
|
||||||
|
|
||||||
// imgui
|
// imgui
|
||||||
|
|||||||
@ -50,9 +50,10 @@ public:
|
|||||||
U32
|
U32
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Renderer(RendererAPI api) : m_rendererAPI(api) {};
|
||||||
virtual ~Renderer() = default;
|
virtual ~Renderer() = default;
|
||||||
|
|
||||||
virtual RendererAPI GetType() = 0;
|
RendererAPI GetType() const { return m_rendererAPI; }
|
||||||
|
|
||||||
virtual void Initialize();
|
virtual void Initialize();
|
||||||
virtual void Shutdown();
|
virtual void Shutdown();
|
||||||
@ -162,6 +163,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void GetVendorInformation() { }
|
virtual void GetVendorInformation() { }
|
||||||
|
RendererAPI m_rendererAPI;
|
||||||
GfxVendor m_vendor = GfxVendor::Generic;
|
GfxVendor m_vendor = GfxVendor::Generic;
|
||||||
|
|
||||||
static uint8 SRGBComponentToRGB(uint8 ci);
|
static uint8 SRGBComponentToRGB(uint8 ci);
|
||||||
|
|||||||
@ -492,7 +492,7 @@ static void LinuxBreathOfTheWildWorkaround(VkInstance& instance, const VkInstanc
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VulkanRenderer::VulkanRenderer()
|
VulkanRenderer::VulkanRenderer() : Renderer(RendererAPI::Vulkan)
|
||||||
{
|
{
|
||||||
glslang::InitializeProcess();
|
glslang::InitializeProcess();
|
||||||
|
|
||||||
@ -908,7 +908,7 @@ VulkanRenderer::~VulkanRenderer()
|
|||||||
defaultShaders.copySurface_psDepth2Color = nullptr;
|
defaultShaders.copySurface_psDepth2Color = nullptr;
|
||||||
|
|
||||||
// destroy misc
|
// destroy misc
|
||||||
for (auto& it : m_cmd_buffer_fences)
|
for (auto& it : m_cmdBufferFences)
|
||||||
{
|
{
|
||||||
vkDestroyFence(m_logicalDevice, it, nullptr);
|
vkDestroyFence(m_logicalDevice, it, nullptr);
|
||||||
it = VK_NULL_HANDLE;
|
it = VK_NULL_HANDLE;
|
||||||
@ -958,11 +958,8 @@ VulkanRenderer::~VulkanRenderer()
|
|||||||
|
|
||||||
VulkanRenderer* VulkanRenderer::GetInstance()
|
VulkanRenderer* VulkanRenderer::GetInstance()
|
||||||
{
|
{
|
||||||
#ifdef CEMU_DEBUG_ASSERT
|
cemu_assert_debug(g_renderer->GetType() == RendererAPI::Vulkan);
|
||||||
cemu_assert_debug(g_renderer && dynamic_cast<VulkanRenderer*>(g_renderer.get()));
|
return static_cast<VulkanRenderer*>(g_renderer.get());
|
||||||
// Use #if here because dynamic_casts dont get optimized away even if the result is not stored as with cemu_assert_debug
|
|
||||||
#endif
|
|
||||||
return (VulkanRenderer*)g_renderer.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::InitializeSurface(const Vector2i& size, bool mainWindow)
|
void VulkanRenderer::InitializeSurface(const Vector2i& size, bool mainWindow)
|
||||||
@ -1664,14 +1661,14 @@ void VulkanRenderer::CreateCommandPool()
|
|||||||
|
|
||||||
void VulkanRenderer::CreateCommandBuffers()
|
void VulkanRenderer::CreateCommandBuffers()
|
||||||
{
|
{
|
||||||
auto it = m_cmd_buffer_fences.begin();
|
auto it = m_cmdBufferFences.begin();
|
||||||
VkFenceCreateInfo fenceInfo{};
|
VkFenceCreateInfo fenceInfo{};
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &*it);
|
vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &*it);
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
fenceInfo.flags = 0;
|
fenceInfo.flags = 0;
|
||||||
for (; it != m_cmd_buffer_fences.end(); ++it)
|
for (; it != m_cmdBufferFences.end(); ++it)
|
||||||
{
|
{
|
||||||
vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &*it);
|
vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &*it);
|
||||||
}
|
}
|
||||||
@ -2131,7 +2128,7 @@ void VulkanRenderer::InitFirstCommandBuffer()
|
|||||||
m_commandBufferSyncIndex = 0;
|
m_commandBufferSyncIndex = 0;
|
||||||
|
|
||||||
m_state.currentCommandBuffer = m_commandBuffers[m_commandBufferIndex];
|
m_state.currentCommandBuffer = m_commandBuffers[m_commandBufferIndex];
|
||||||
vkResetFences(m_logicalDevice, 1, &m_cmd_buffer_fences[m_commandBufferIndex]);
|
vkResetFences(m_logicalDevice, 1, &m_cmdBufferFences[m_commandBufferIndex]);
|
||||||
VkCommandBufferBeginInfo beginInfo{};
|
VkCommandBufferBeginInfo beginInfo{};
|
||||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
@ -2148,7 +2145,7 @@ void VulkanRenderer::ProcessFinishedCommandBuffers()
|
|||||||
bool finishedCmdBuffers = false;
|
bool finishedCmdBuffers = false;
|
||||||
while (m_commandBufferSyncIndex != m_commandBufferIndex)
|
while (m_commandBufferSyncIndex != m_commandBufferIndex)
|
||||||
{
|
{
|
||||||
VkResult fenceStatus = vkGetFenceStatus(m_logicalDevice, m_cmd_buffer_fences[m_commandBufferSyncIndex]);
|
VkResult fenceStatus = vkGetFenceStatus(m_logicalDevice, m_cmdBufferFences[m_commandBufferSyncIndex]);
|
||||||
if (fenceStatus == VK_SUCCESS)
|
if (fenceStatus == VK_SUCCESS)
|
||||||
{
|
{
|
||||||
ProcessDestructionQueue();
|
ProcessDestructionQueue();
|
||||||
@ -2177,7 +2174,7 @@ void VulkanRenderer::WaitForNextFinishedCommandBuffer()
|
|||||||
{
|
{
|
||||||
cemu_assert_debug(m_commandBufferSyncIndex != m_commandBufferIndex);
|
cemu_assert_debug(m_commandBufferSyncIndex != m_commandBufferIndex);
|
||||||
// wait on least recently submitted command buffer
|
// wait on least recently submitted command buffer
|
||||||
VkResult result = vkWaitForFences(m_logicalDevice, 1, &m_cmd_buffer_fences[m_commandBufferSyncIndex], true, UINT64_MAX);
|
VkResult result = vkWaitForFences(m_logicalDevice, 1, &m_cmdBufferFences[m_commandBufferSyncIndex], true, UINT64_MAX);
|
||||||
if (result == VK_TIMEOUT)
|
if (result == VK_TIMEOUT)
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "vkWaitForFences: Returned VK_TIMEOUT on infinite fence");
|
cemuLog_log(LogType::Force, "vkWaitForFences: Returned VK_TIMEOUT on infinite fence");
|
||||||
@ -2230,7 +2227,7 @@ void VulkanRenderer::SubmitCommandBuffer(VkSemaphore signalSemaphore, VkSemaphor
|
|||||||
submitInfo.pWaitDstStageMask = semWaitStageMask;
|
submitInfo.pWaitDstStageMask = semWaitStageMask;
|
||||||
submitInfo.pWaitSemaphores = waitSemArray;
|
submitInfo.pWaitSemaphores = waitSemArray;
|
||||||
|
|
||||||
const VkResult result = vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_cmd_buffer_fences[m_commandBufferIndex]);
|
const VkResult result = vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_cmdBufferFences[m_commandBufferIndex]);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
UnrecoverableError(fmt::format("failed to submit command buffer. Error {}", result).c_str());
|
UnrecoverableError(fmt::format("failed to submit command buffer. Error {}", result).c_str());
|
||||||
m_numSubmittedCmdBuffers++;
|
m_numSubmittedCmdBuffers++;
|
||||||
@ -2251,7 +2248,7 @@ void VulkanRenderer::SubmitCommandBuffer(VkSemaphore signalSemaphore, VkSemaphor
|
|||||||
|
|
||||||
|
|
||||||
m_state.currentCommandBuffer = m_commandBuffers[m_commandBufferIndex];
|
m_state.currentCommandBuffer = m_commandBuffers[m_commandBufferIndex];
|
||||||
vkResetFences(m_logicalDevice, 1, &m_cmd_buffer_fences[m_commandBufferIndex]);
|
vkResetFences(m_logicalDevice, 1, &m_cmdBufferFences[m_commandBufferIndex]);
|
||||||
vkResetCommandBuffer(m_state.currentCommandBuffer, 0);
|
vkResetCommandBuffer(m_state.currentCommandBuffer, 0);
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo{};
|
VkCommandBufferBeginInfo beginInfo{};
|
||||||
|
|||||||
@ -89,7 +89,7 @@ public:
|
|||||||
};
|
};
|
||||||
using DescriptorSetCache = ska::flat_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>>;
|
using DescriptorSetCache = ska::flat_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>>;
|
||||||
|
|
||||||
FORCEINLINE DescriptorSetCache& GetDescriptorSetCache(LatteConst::ShaderType shaderType)
|
FORCE_INLINE DescriptorSetCache& GetDescriptorSetCache(LatteConst::ShaderType shaderType)
|
||||||
{
|
{
|
||||||
cemu_assert_debug(shaderType == LatteConst::ShaderType::Vertex || shaderType == LatteConst::ShaderType::Pixel || shaderType == LatteConst::ShaderType::Geometry);
|
cemu_assert_debug(shaderType == LatteConst::ShaderType::Vertex || shaderType == LatteConst::ShaderType::Pixel || shaderType == LatteConst::ShaderType::Geometry);
|
||||||
return ds_cache[static_cast<size_t>(shaderType)];
|
return ds_cache[static_cast<size_t>(shaderType)];
|
||||||
@ -189,8 +189,6 @@ public:
|
|||||||
VulkanRenderer();
|
VulkanRenderer();
|
||||||
virtual ~VulkanRenderer();
|
virtual ~VulkanRenderer();
|
||||||
|
|
||||||
RendererAPI GetType() override { return RendererAPI::Vulkan; }
|
|
||||||
|
|
||||||
static VulkanRenderer* GetInstance();
|
static VulkanRenderer* GetInstance();
|
||||||
|
|
||||||
void UnrecoverableError(const char* errMsg) const;
|
void UnrecoverableError(const char* errMsg) const;
|
||||||
@ -661,8 +659,8 @@ private:
|
|||||||
size_t m_commandBufferIndex = 0; // current buffer being filled
|
size_t m_commandBufferIndex = 0; // current buffer being filled
|
||||||
size_t m_commandBufferSyncIndex = 0; // latest buffer that finished execution (updated on submit)
|
size_t m_commandBufferSyncIndex = 0; // latest buffer that finished execution (updated on submit)
|
||||||
size_t m_commandBufferIDOfPrevFrame = 0;
|
size_t m_commandBufferIDOfPrevFrame = 0;
|
||||||
std::array<size_t, kCommandBufferPoolSize> m_cmdBufferUniformRingbufIndices {}; // index in the uniform ringbuffer
|
std::array<size_t, kCommandBufferPoolSize> m_cmdBufferUniformRingbufIndices {}; // read index in the uniform ringbuffer after the command buffer finishes
|
||||||
std::array<VkFence, kCommandBufferPoolSize> m_cmd_buffer_fences;
|
std::array<VkFence, kCommandBufferPoolSize> m_cmdBufferFences;
|
||||||
std::array<VkCommandBuffer, kCommandBufferPoolSize> m_commandBuffers;
|
std::array<VkCommandBuffer, kCommandBufferPoolSize> m_commandBuffers;
|
||||||
std::array<VkSemaphore, kCommandBufferPoolSize> m_commandBufferSemaphores;
|
std::array<VkSemaphore, kCommandBufferPoolSize> m_commandBufferSemaphores;
|
||||||
|
|
||||||
|
|||||||
@ -320,23 +320,18 @@ uint32 VulkanRenderer::uniformData_uploadUniformDataBufferGetOffset(std::span<ui
|
|||||||
const uint32 bufferAlignmentM1 = m_featureControl.limits.calcUniformBufferAlignmentM1;
|
const uint32 bufferAlignmentM1 = m_featureControl.limits.calcUniformBufferAlignmentM1;
|
||||||
const uint32 uniformSize = ((uint32)data.size() + bufferAlignmentM1) & ~bufferAlignmentM1;
|
const uint32 uniformSize = ((uint32)data.size() + bufferAlignmentM1) & ~bufferAlignmentM1;
|
||||||
|
|
||||||
auto waitWhileCondition = [&](std::function<bool()> condition) {
|
auto waitWhileCondition = [&]<class TCondition>(TCondition&& condition) {
|
||||||
while (condition())
|
while (condition())
|
||||||
{
|
{
|
||||||
if (m_commandBufferSyncIndex == m_commandBufferIndex)
|
if (m_commandBufferSyncIndex == m_commandBufferIndex)
|
||||||
{
|
{
|
||||||
if (m_cmdBufferUniformRingbufIndices[m_commandBufferIndex] != m_uniformVarBufferReadIndex)
|
// we caught up to the current command buffer and there is still not enough space in the uniform ringbuffer
|
||||||
{
|
// in this case we just accept the corruption. In practice this is very unlikely to happen with recent reductions to uniform size
|
||||||
draw_endRenderPass();
|
// If this does continue to be an issue then the likely easiest solution is to start a new command buffer at the end of a draw sequence if the ringbuffer is filled beyond a certain threshold
|
||||||
SubmitCommandBuffer();
|
// submitting the command buffere here is complicated because we'd have to restore all of the dynamic state
|
||||||
}
|
cemuLog_log(LogType::Force, "Vulkan: Uniform ring buffer overflowed. Expect visual corruption");
|
||||||
else
|
cemu_assert_suspicious();
|
||||||
{
|
break;
|
||||||
// submitting work would not change readIndex, so there's no way for conditions based on it to change
|
|
||||||
cemuLog_log(LogType::Force, "draw call overflowed and corrupted uniform ringbuffer. expect visual corruption");
|
|
||||||
cemu_assert_suspicious();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
WaitForNextFinishedCommandBuffer();
|
WaitForNextFinishedCommandBuffer();
|
||||||
}
|
}
|
||||||
@ -1650,7 +1645,7 @@ void VulkanRenderer::draw_execute_continued(uint32 baseVertex, uint32 baseInstan
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
__debugbreak(); // should never happen unless draw_prepareDescriptorSets can fail?
|
cemu_assert(false); // should never happen unless draw_prepareDescriptorSets can fail?
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_setRenderPass();
|
draw_setRenderPass();
|
||||||
|
|||||||
@ -199,10 +199,9 @@ void GX2CopySurfaceInternal(GX2Surface* srcSurface, uint32 srcMip, uint32 srcSli
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// make sure formats are compatible
|
// make sure formats are compatible
|
||||||
if( srcHwFormat != dstHwFormat )
|
if( surfOutSrc.bpp != surfOutDst.bpp )
|
||||||
{
|
{
|
||||||
// mismatching format
|
cemuLog_logDebug(LogType::Force, "GX2CopySurface(): Format bpp mismatch (src=0x{:04x} dst=0x{:04x})", (sint32)srcFormat, (sint32)dstFormat);
|
||||||
cemuLog_logDebug(LogType::Force, "GX2CopySurface(): Format mismatch (src=0x{:04x} dst=0x{:04x})", (sint32)srcFormat, (sint32)dstFormat);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// get input pointer
|
// get input pointer
|
||||||
|
|||||||
@ -28,6 +28,7 @@ add_library(CemuUtil
|
|||||||
helpers/MapAdaptor.h
|
helpers/MapAdaptor.h
|
||||||
helpers/MemoryPool.h
|
helpers/MemoryPool.h
|
||||||
helpers/ringbuffer.h
|
helpers/ringbuffer.h
|
||||||
|
helpers/StateHasher.h
|
||||||
helpers/Semaphore.h
|
helpers/Semaphore.h
|
||||||
helpers/Serializer.cpp
|
helpers/Serializer.cpp
|
||||||
helpers/Serializer.h
|
helpers/Serializer.h
|
||||||
|
|||||||
@ -5,27 +5,27 @@
|
|||||||
class DualStateHasher
|
class DualStateHasher
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FORCEINLINE DualStateHasher()
|
FORCE_INLINE DualStateHasher()
|
||||||
{
|
{
|
||||||
m_h0 = 0x9E3779B97F4A7C15;
|
m_h0 = 0x9E3779B97F4A7C15;
|
||||||
m_h1 = 0xC2B2AE3D27D4EB4F;
|
m_h1 = 0xC2B2AE3D27D4EB4F;
|
||||||
};
|
};
|
||||||
|
|
||||||
FORCEINLINE void MixIn(uint64 a, uint64 b)
|
FORCE_INLINE void MixIn(uint64 a, uint64 b)
|
||||||
{
|
{
|
||||||
uint64 tmp = m_h1;
|
uint64 tmp = m_h1;
|
||||||
m_h1 = (m_h0 ^ a) * 0x85EBCA77C2B2AE63ULL;
|
m_h1 = (m_h0 ^ a) * 0x85EBCA77C2B2AE63ULL;
|
||||||
m_h0 = (tmp ^ b) * 0x165667B19E3779F9ULL;
|
m_h0 = (tmp ^ b) * 0x165667B19E3779F9ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE void MixInSingle(uint64 a)
|
FORCE_INLINE void MixInSingle(uint64 a)
|
||||||
{
|
{
|
||||||
uint64 tmp = m_h1;
|
uint64 tmp = m_h1;
|
||||||
m_h1 = (m_h0 ^ a) * 0x85EBCA77C2B2AE63ULL;
|
m_h1 = (m_h0 ^ a) * 0x85EBCA77C2B2AE63ULL;
|
||||||
m_h0 = tmp;
|
m_h0 = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE uint64 Finish()
|
FORCE_INLINE uint64 Finish()
|
||||||
{
|
{
|
||||||
uint64 combined = m_h0 ^ std::rotl(m_h1, 31);
|
uint64 combined = m_h0 ^ std::rotl(m_h1, 31);
|
||||||
combined ^= combined >> 33;
|
combined ^= combined >> 33;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user