[Perf] (MG_Backend/DirectVulkan): drop redundant per-draw work in UploadAndBindVertexBuffers - pass programObj from SetupDraw, use the VAO attribute's buffer SharedPtr directly instead of re-resolving by external index; 8.5%->6.2%

This commit is contained in:
2026-07-13 05:21:57 -04:00
parent 7fe5247626
commit 37cd5b42de
2 changed files with 16 additions and 17 deletions
@@ -2165,11 +2165,11 @@ void main() {
} }
Bool VulkanRenderer::UploadAndBindVertexBuffers( Bool VulkanRenderer::UploadAndBindVertexBuffers(
VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao, const DrawCmdParam& drawParams) { VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao,
const ProgramFactory::VkProgramObject& programObj, const DrawCmdParam& drawParams) {
// programObj is resolved once in SetupDraw and passed in; re-resolving it here would repeat
// the GetCurrentProgram + GetOrCreateProgram hash lookup every draw.
auto& vertexInputState = m_vertexInputStateFactory->GetOrCreateVertexInputState(vao); auto& vertexInputState = m_vertexInputStateFactory->GetOrCreateVertexInputState(vao);
const auto& program = *MG_State::pGLContext->GetCurrentProgram();
const auto transformFlags = GetShaderTransformFlags(m_swapchainObject.GetPreTransform());
const auto& programObj = m_programFactory->GetOrCreateProgram(program, transformFlags);
const Uint32 activeAttribMask = programObj.activeVertexInputLocationMask; const Uint32 activeAttribMask = programObj.activeVertexInputLocationMask;
const Uint32 vertexInputAttribMask = BuildVertexInputAttributeMask(vertexInputState.attributes); const Uint32 vertexInputAttribMask = BuildVertexInputAttributeMask(vertexInputState.attributes);
const Uint32 missingAttribMask = activeAttribMask & ~vertexInputAttribMask; const Uint32 missingAttribMask = activeAttribMask & ~vertexInputAttribMask;
@@ -2181,16 +2181,12 @@ void main() {
vkBuffers.assign(bindingCount, VK_NULL_HANDLE); vkBuffers.assign(bindingCount, VK_NULL_HANDLE);
vkOffsets.assign(bindingCount, 0); vkOffsets.assign(bindingCount, 0);
auto findBufferByKey = [&](SizeT bufferKey) -> const MG_State::GLState::BufferObject* { auto findBufferByKey = [&](SizeT bufferKey) -> const SharedPtr<MG_State::GLState::BufferObject>* {
const auto& attrs = vao.GetAllAttributes(); const auto& attrs = vao.GetAllAttributes();
for (Uint32 location = 0; location < MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS; ++location) { for (Uint32 location = 0; location < MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS; ++location) {
const auto& attr = attrs[location]; const auto& attr = attrs[location];
if (!attr.Buffer) { if (attr.Buffer && reinterpret_cast<SizeT>(attr.Buffer.get()) == bufferKey) {
continue; return &attr.Buffer;
}
const auto* buffer = attr.Buffer.get();
if (reinterpret_cast<SizeT>(buffer) == bufferKey) {
return buffer;
} }
} }
return nullptr; return nullptr;
@@ -2243,11 +2239,13 @@ void main() {
} }
const SizeT bufferKey = vertexInputState.bindingBufferKeys[binding]; const SizeT bufferKey = vertexInputState.bindingBufferKeys[binding];
const MG_State::GLState::BufferObject* sourceBuffer = findBufferByKey(bufferKey); // The VAO attribute already holds the buffer's SharedPtr; use it by reference directly
MOBILEGL_ASSERT(sourceBuffer != nullptr, "UploadAndBindVertexStreams failed to resolve source buffer"); // instead of re-resolving it from the GL context by external index (a map lookup +
auto sourceBufferShared = MG_State::pGLContext->GetBufferObject(sourceBuffer->GetExternalIndex()); // atomic refcount every binding every draw).
MOBILEGL_ASSERT(sourceBufferShared != nullptr, const SharedPtr<MG_State::GLState::BufferObject>* sourceBufferSharedPtr = findBufferByKey(bufferKey);
"UploadAndBindVertexStreams failed to resolve shared source buffer"); MOBILEGL_ASSERT(sourceBufferSharedPtr != nullptr && *sourceBufferSharedPtr != nullptr,
"UploadAndBindVertexStreams failed to resolve source buffer");
const auto& sourceBufferShared = *sourceBufferSharedPtr;
BufferSlice slice{}; BufferSlice slice{};
const SizeT sourceSize = sourceBufferShared->GetSize(); const SizeT sourceSize = sourceBufferShared->GetSize();
if (ShouldUseTransientVertexIndexBuffer(*sourceBufferShared)) { if (ShouldUseTransientVertexIndexBuffer(*sourceBufferShared)) {
@@ -3564,7 +3562,7 @@ void main() {
return false; return false;
} }
auto vtxUploadOk = UploadAndBindVertexBuffers(frame.commandBuffer, vao, drawParams); auto vtxUploadOk = UploadAndBindVertexBuffers(frame.commandBuffer, vao, programObj, drawParams);
if (!vtxUploadOk) { if (!vtxUploadOk) {
MGLOG_E("SetupDraw skipped: failed to upload vertex buffers"); MGLOG_E("SetupDraw skipped: failed to upload vertex buffers");
return false; return false;
@@ -448,6 +448,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DestroyComputePipelines(); void DestroyComputePipelines();
Bool UploadAndBindVertexBuffers(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao, Bool UploadAndBindVertexBuffers(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao,
const ProgramFactory::VkProgramObject& programObj,
const DrawCmdParam& drawParams); const DrawCmdParam& drawParams);
Bool UploadAndBindIndexBuffer(FrameContext::FrameData& frame, Bool UploadAndBindIndexBuffer(FrameContext::FrameData& frame,
const MG_State::GLState::VertexArrayObject& vao, const MG_State::GLState::VertexArrayObject& vao,