diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 5cb6e811..44ff6df6 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -524,6 +524,57 @@ namespace MobileGL::MG_Backend::DirectVulkan { return true; } + Bool VulkanRenderer::UploadAndBindIndexBuffer(FrameContext::FrameData& frame, + const MG_State::GLState::VertexArrayObject& vao, + GLenum indexType, + SizeT indexByteOffset, + Uint32 indexCount) { + VkIndexType vkIndexType = VK_INDEX_TYPE_MAX_ENUM; + switch (indexType) { + case GL_UNSIGNED_SHORT: + vkIndexType = VK_INDEX_TYPE_UINT16; + break; + case GL_UNSIGNED_INT: + vkIndexType = VK_INDEX_TYPE_UINT32; + break; + default: + MGLOG_D("DrawElements skipped: index type %u is not supported yet", indexType); + return false; + } + + const auto* indexBuffer = vao.GetIndexBufferBindingSlot().GetBoundObject().get(); + MOBILEGL_ASSERT(indexBuffer != nullptr, "UploadAndBindIndexBuffer requires bound EBO"); + const auto indexData = indexBuffer->GetDataReadOnly(); + MOBILEGL_ASSERT(indexData != nullptr && !indexData->empty(), "DrawElements requires non-empty EBO data"); + + const SizeT indexSize = (indexType == GL_UNSIGNED_SHORT) ? sizeof(Uint16) : sizeof(Uint32); + const SizeT indexDataSizeBytes = static_cast(indexCount) * indexSize; + MOBILEGL_ASSERT(indexByteOffset + indexDataSizeBytes <= indexBuffer->GetSize(), + "DrawElements index range out of bounds"); + + const Uint32 frameIndex = m_frameContext.GetCurrentFrameIndex(); + VkDeviceSize& frameIndexHead = m_frameIndexUploadHeads[frameIndex]; + const VkDeviceSize alignment = static_cast(indexSize); + const VkDeviceSize writeOffset = (frameIndexHead + alignment - 1) & ~(alignment - 1); + const VkDeviceSize writeEnd = writeOffset + static_cast(indexDataSizeBytes); + if (!EnsureFrameUploadBufferCapacity(frameIndex, true, writeEnd, 1 * 1024 * 1024, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT)) { + MGLOG_E("DrawElements skipped: failed to prepare index upload buffer"); + return false; + } + + auto& frameIndexUploadBuffer = m_frameIndexUploadBuffers[frameIndex]; + if (!frameIndexUploadBuffer.Upload(indexData->data() + indexByteOffset, + static_cast(indexDataSizeBytes), writeOffset)) { + MGLOG_E("DrawElements skipped: failed to upload index data"); + return false; + } + + frameIndexHead = writeEnd; + vkCmdBindIndexBuffer(frame.commandBuffer, frameIndexUploadBuffer.GetHandle(), writeOffset, vkIndexType); + return true; + } + Bool VulkanRenderer::InitializeBlitResources() { ShutdownBlitResources(); @@ -719,7 +770,8 @@ void main() { return m_pipelineFactory->GetOrCreatePipeline(payload); } - void VulkanRenderer::SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags aspects) { + Bool VulkanRenderer::SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags aspects, + GLenum indexType, SizeT indexByteOffset, Uint32 indexCount) { m_textureManager->CollectGarbage(); const auto& drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); @@ -828,7 +880,15 @@ void main() { m_uniformDescriptorBinder->BindProgramUniformBuffers(frame.commandBuffer, program, m_frameContext.GetCurrentFrameIndex()); - UploadAndBindVertexStreams(frame.commandBuffer, vao); + if (!UploadAndBindVertexStreams(frame.commandBuffer, vao)) { + MGLOG_E("SetupDraw skipped: failed to upload vertex streams"); + return false; + } + if (aspects & DrawSetupAspect::IndexBuffer) { + if (!UploadAndBindIndexBuffer(frame, vao, indexType, indexByteOffset, indexCount)) { + return false; + } + } VkViewport viewport{}; viewport.x = 0.0f; @@ -850,6 +910,7 @@ void main() { scissor.extent = { (Uint)renderPassEntry.extent.x(), (Uint)renderPassEntry.extent.y() }; } vkCmdSetScissor(frame.commandBuffer, 0, 1, &scissor); + return true; } void VulkanRenderer::Clear(GLbitfield mask) { @@ -1194,7 +1255,9 @@ void main() { void VulkanRenderer::DrawArrays(const DrawCmd& payload) { auto& frame = m_frameContext.GetCurrent(); - SetupDraw(frame, payload.mode, 0); + if (!SetupDraw(frame, payload.mode, 0)) { + return; + } MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__); @@ -1210,56 +1273,15 @@ void main() { void VulkanRenderer::DrawElements(const DrawIndexedCmd& payload) { auto& frame = m_frameContext.GetCurrent(); - SetupDraw(frame, payload.mode, 0); - - if (!frame.isCommandRecording) { - MGLOG_D("DrawElements skipped: frame recording was not started"); + if (!SetupDraw(frame, payload.mode, DrawSetupAspect::IndexBuffer, + payload.indexType, payload.indexByteOffset, payload.indexCount)) { return; } - VkIndexType vkIndexType = VK_INDEX_TYPE_MAX_ENUM; - switch (payload.indexType) { - case GL_UNSIGNED_SHORT: - vkIndexType = VK_INDEX_TYPE_UINT16; - break; - case GL_UNSIGNED_INT: - vkIndexType = VK_INDEX_TYPE_UINT32; - break; - default: - MGLOG_D("DrawElements skipped: index type %u is not supported yet", payload.indexType); - return; - } - - auto* vao = MG_State::pGLContext->GetBoundVertexArray().get(); - const auto* indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject().get(); - const auto indexData = indexBuffer->GetDataReadOnly(); - MOBILEGL_ASSERT(indexData != nullptr && !indexData->empty(), "DrawElements requires non-empty EBO data"); - const SizeT indexSize = (payload.indexType == GL_UNSIGNED_SHORT) ? sizeof(Uint16) : sizeof(Uint32); - const SizeT indexDataSizeBytes = static_cast(payload.indexCount) * indexSize; - MOBILEGL_ASSERT(payload.indexByteOffset + indexDataSizeBytes <= indexBuffer->GetSize(), - "DrawElements index range out of bounds"); - - const Uint32 frameIndex = m_frameContext.GetCurrentFrameIndex(); - VkDeviceSize& frameIndexHead = m_frameIndexUploadHeads[frameIndex]; - const VkDeviceSize alignment = static_cast(indexSize); - const VkDeviceSize writeOffset = (frameIndexHead + alignment - 1) & ~(alignment - 1); - const VkDeviceSize writeEnd = writeOffset + static_cast(indexDataSizeBytes); - if (!EnsureFrameUploadBufferCapacity(frameIndex, true, writeEnd, 1 * 1024 * 1024, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT)) { - MGLOG_E("DrawElements skipped: failed to prepare index upload buffer"); - return; - } - auto& frameIndexUploadBuffer = m_frameIndexUploadBuffers[frameIndex]; - if (!frameIndexUploadBuffer.Upload(indexData->data() + payload.indexByteOffset, - static_cast(indexDataSizeBytes), writeOffset)) { - MGLOG_E("DrawElements skipped: failed to upload index data"); - return; - } - frameIndexHead = writeEnd; + MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__); VkCommandBuffer& commandBuffer = frame.commandBuffer; - vkCmdBindIndexBuffer(commandBuffer, frameIndexUploadBuffer.GetHandle(), writeOffset, vkIndexType); vkCmdDrawIndexed(commandBuffer, payload.indexCount, payload.instanceCount, diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index 29df7585..cd29223c 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -92,7 +92,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { void Initialize(); void Shutdown(); - void SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags aspects); + Bool SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags aspects, + GLenum indexType = 0, SizeT indexByteOffset = 0, Uint32 indexCount = 0); void ClearAttachmentsOnActiveRenderPass(VkCommandBuffer commandBuffer, const RenderPassEntry& compatibleRenderPassEntry); @@ -196,6 +197,11 @@ namespace MobileGL::MG_Backend::DirectVulkan { Bool EnsureFrameUploadBufferCapacity(Uint32 frameIndex, Bool isIndexBuffer, VkDeviceSize requiredEndOffset, VkDeviceSize minCapacity, VkBufferUsageFlags usage); Bool UploadAndBindVertexStreams(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao); + Bool UploadAndBindIndexBuffer(FrameContext::FrameData& frame, + const MG_State::GLState::VertexArrayObject& vao, + GLenum indexType, + SizeT indexByteOffset, + Uint32 indexCount); Bool InitializeBlitResources(); void ShutdownBlitResources(); Bool TryBlitToDefaultFramebufferWithShader(FrameContext::FrameData& frame,