diff --git a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp index c4cadc97..61e0aa8c 100644 --- a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp @@ -55,8 +55,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { DrawCmd payload{}; payload.mode = mode; - payload.firstVertex = first; - payload.vertexCount = count; + payload.params.firstVertex = first; + payload.params.vertexCount = count; pVulkanRenderer->DrawArrays(payload); } @@ -69,8 +69,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { payload.mode = mode; payload.indexBufferView.indexType = type; payload.indexBufferView.indexByteOffset = reinterpret_cast(indices); - payload.indexCount = count; - payload.instanceCount = 1; + payload.indexBufferView.indexByteSize = count * MG_Util::GetGLTypeSize(type); + payload.params.indexCount = count; + payload.params.instanceCount = 1; pVulkanRenderer->DrawElements(payload); } @@ -109,11 +110,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { payload.mode = mode; payload.indexBufferView.indexType = type; payload.indexBufferView.indexByteOffset = reinterpret_cast(indices); - payload.indexCount = count; - payload.instanceCount = 1; - payload.firstIndex = 0; - payload.vertexOffset = basevertex; - payload.firstInstance = 0; + payload.indexBufferView.indexByteSize = count * MG_Util::GetGLTypeSize(type); + payload.params.indexCount = count; + payload.params.instanceCount = 1; + payload.params.firstIndex = 0; + payload.params.vertexOffset = basevertex; + payload.params.firstInstance = 0; pVulkanRenderer->DrawElements(payload); } @@ -121,13 +123,38 @@ namespace MobileGL::MG_Backend::DirectVulkan { GLsizei drawcount, const GLint* basevertex) { MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer"); MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context"); - // TODO: properly batch the draw calls + MultiDrawIndexedCmd payload{}; + payload.mode = mode; + payload.indexBufferView.indexType = type; + + // TODO: allocate draw cmd buf elsewhere + static Vector params; + params.clear(); + params.resize(drawcount); + for (GLsizei i = 0; i < drawcount; ++i) { if (count[i] == 0) { - continue; + continue; } - DrawElementsBaseVertex(mode, count[i], type, indices[i], basevertex[i]); + + // TODO: this index view needs a redesign, now there's a lotta redundant uploads + + payload.indexBufferView.indexByteOffset = 0; + payload.indexBufferView.indexByteSize = + std::max(reinterpret_cast(indices[i]) + count[i] * MG_Util::GetGLTypeSize(type), + payload.indexBufferView.indexByteSize); + + auto& param = params[i]; + + param.indexCount = count[i]; + param.instanceCount = 1; + param.firstIndex = reinterpret_cast(indices[i]) / MG_Util::GetGLTypeSize(type); + param.vertexOffset = basevertex[i]; + param.firstInstance = 0; } + payload.drawCount = drawcount; + payload.pParams = params.data(); + pVulkanRenderer->MultiDrawElements(payload); } void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 2650cde1..388159c6 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -399,7 +399,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { vkDestroyDevice(m_device, nullptr); m_device = VK_NULL_HANDLE; } - m_cmdDrawIndexedIndirectCount = nullptr; + s_vkCmdDrawIndexedIndirectCount = nullptr; if (m_surface != VK_NULL_HANDLE) { vkDestroySurfaceKHR(m_instance, m_surface, nullptr); @@ -526,11 +526,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { Bool VulkanRenderer::UploadAndBindIndexBuffer(FrameContext::FrameData& frame, const MG_State::GLState::VertexArrayObject& vao, - GLenum indexType, - SizeT indexByteOffset, - Uint32 indexCount) { + const IndexBufferView* pIndexBufferView) { VkIndexType vkIndexType = VK_INDEX_TYPE_MAX_ENUM; - switch (indexType) { + switch (pIndexBufferView->indexType) { case GL_UNSIGNED_SHORT: vkIndexType = VK_INDEX_TYPE_UINT16; break; @@ -538,7 +536,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { vkIndexType = VK_INDEX_TYPE_UINT32; break; default: - MGLOG_D("DrawElements skipped: index type %u is not supported yet", indexType); + MGLOG_D("DrawElements skipped: index type %u is not supported yet", pIndexBufferView->indexType); return false; } @@ -547,14 +545,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { 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(), + const SizeT indexSize = MG_Util::GetGLTypeSize(pIndexBufferView->indexType); + const SizeT indexDataSizeBytes = pIndexBufferView->indexByteSize; + MOBILEGL_ASSERT(pIndexBufferView->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 alignment = indexSize; const VkDeviceSize writeOffset = (frameIndexHead + alignment - 1) & ~(alignment - 1); const VkDeviceSize writeEnd = writeOffset + static_cast(indexDataSizeBytes); if (!EnsureFrameUploadBufferCapacity(frameIndex, true, writeEnd, 1 * 1024 * 1024, @@ -564,7 +562,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } auto& frameIndexUploadBuffer = m_frameIndexUploadBuffers[frameIndex]; - if (!frameIndexUploadBuffer.Upload(indexData->data() + indexByteOffset, + if (!frameIndexUploadBuffer.Upload(indexData->data() + pIndexBufferView->indexByteOffset, static_cast(indexDataSizeBytes), writeOffset)) { MGLOG_E("DrawElements skipped: failed to upload index data"); return false; @@ -771,7 +769,7 @@ void main() { } void VulkanRenderer::SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags aspects, - GLenum indexType, SizeT indexByteOffset, Uint32 indexCount) { + const IndexBufferView* pIndexBufferView) { m_textureManager->CollectGarbage(); const auto& drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); @@ -884,7 +882,7 @@ void main() { MOBILEGL_ASSERT(vtxUploadOk, "SetupDraw skipped: failed to upload vertex streams"); if (aspects & DrawSetupAspect::IndexBuffer) { - auto idxUploadOk = UploadAndBindIndexBuffer(frame, vao, indexType, indexByteOffset, indexCount); + auto idxUploadOk = UploadAndBindIndexBuffer(frame, vao, pIndexBufferView); MOBILEGL_ASSERT(idxUploadOk, "SetupDraw skipped: failed to upload index buffer"); } @@ -1259,32 +1257,48 @@ void main() { VkCommandBuffer& commandBuffer = frame.commandBuffer; vkCmdDraw(commandBuffer, - payload.vertexCount, - payload.instanceCount, - payload.firstVertex, - payload.firstInstance); + payload.params.vertexCount, + payload.params.instanceCount, + payload.params.firstVertex, + payload.params.firstInstance); } void VulkanRenderer::DrawElements(const DrawIndexedCmd& payload) { auto& frame = m_frameContext.GetCurrent(); SetupDraw(frame, payload.mode, DrawSetupAspect::IndexBuffer, - payload.indexBufferView.indexType, payload.indexBufferView.indexByteOffset, payload.indexCount); + &payload.indexBufferView); MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__); VkCommandBuffer& commandBuffer = frame.commandBuffer; vkCmdDrawIndexed(commandBuffer, - payload.indexCount, - payload.instanceCount, - payload.firstIndex, - payload.vertexOffset, - payload.firstInstance); + payload.params.indexCount, + payload.params.instanceCount, + payload.params.firstIndex, + payload.params.vertexOffset, + payload.params.firstInstance); } - void VulkanRenderer::MultiDrawElements(const Vector& payloads) { + void VulkanRenderer::MultiDrawElements(const MultiDrawIndexedCmd& payload) { + auto& frame = m_frameContext.GetCurrent(); + SetupDraw(frame, payload.mode, DrawSetupAspect::IndexBuffer, + &payload.indexBufferView); + + MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__); + + VkCommandBuffer& commandBuffer = frame.commandBuffer; + + for (Uint32 idraw = 0; idraw < payload.drawCount; ++idraw) { + vkCmdDrawIndexed(commandBuffer, + payload.pParams[idraw].indexCount, + payload.pParams[idraw].instanceCount, + payload.pParams[idraw].firstIndex, + payload.pParams[idraw].vertexOffset, + payload.pParams[idraw].firstInstance); + } } void VulkanRenderer::Present() { @@ -1639,14 +1653,15 @@ void main() { deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data(); VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice"); - m_cmdDrawIndexedIndirectCount = reinterpret_cast( + s_vkCmdDrawIndexedIndirectCount = reinterpret_cast( vkGetDeviceProcAddr(m_device, "vkCmdDrawIndexedIndirectCountKHR")); - if (m_cmdDrawIndexedIndirectCount == nullptr) { - m_cmdDrawIndexedIndirectCount = reinterpret_cast( + if (s_vkCmdDrawIndexedIndirectCount == nullptr) { + s_vkCmdDrawIndexedIndirectCount = reinterpret_cast( vkGetDeviceProcAddr(m_device, "vkCmdDrawIndexedIndirectCount")); } - if (m_drawIndirectCountExtensionEnabled && m_cmdDrawIndexedIndirectCount == nullptr) { - MGLOG_W("VK_KHR_draw_indirect_count enabled but vkCmdDrawIndexedIndirectCount entry point is missing"); + if (m_drawIndirectCountExtensionEnabled && s_vkCmdDrawIndexedIndirectCount == nullptr) { + MGLOG_W("VK_KHR_draw_indirect_count enabled but vkCmdDrawIndexedIndirectCount entry point is missing, will continue as if VK_KHR_draw_indirect_count is not supported!"); + m_drawIndirectCountExtensionEnabled = false; } MGLOG_I("Logical device created."); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index f205a544..2feec343 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -34,34 +34,24 @@ namespace MobileGL::MG_State::GLState { namespace MobileGL::MG_Backend::DirectVulkan { enum class DrawSetupAspect: Uint8 { - FramebufferObject = 1 << 0, - VertexArrayObject = 1 << 1, - UniformBuffer = 1 << 2, - VertexBuffer = 1 << 3, - IndexBuffer = 1 << 4, - Viewport = 1 << 5, - Scissor = 1 << 6, + FramebufferObject = 1 << 0, + VertexArrayObject = 1 << 1, + UniformBuffer = 1 << 2, + VertexBuffer = 1 << 3, + IndexBuffer = 1 << 4, + IndirectDrawBuffer = 1 << 5, + Viewport = 1 << 6, + Scissor = 1 << 7, }; - struct DrawBaseCmd { - GLenum mode = GL_TRIANGLES; - }; - - struct DrawCmd: public DrawBaseCmd { + struct DrawCmdParam { Uint32 vertexCount = 0; Uint32 instanceCount = 1; Uint32 firstVertex = 0; Uint32 firstInstance = 0; }; - struct IndexBufferView { - GLenum indexType = GL_UNSIGNED_SHORT; - SizeT indexByteOffset = 0; - }; - - struct DrawIndexedCmd: public DrawBaseCmd { - IndexBufferView indexBufferView; - + struct DrawIndexedCmdParam { Uint32 indexCount = 0; Uint32 instanceCount = 1; Uint32 firstIndex = 0; @@ -69,8 +59,30 @@ namespace MobileGL::MG_Backend::DirectVulkan { Int32 firstInstance = 0; }; - struct MultiDrawElementsCmd { + struct DrawCmd { + GLenum mode = GL_TRIANGLES; + DrawCmdParam params; + }; + struct IndexBufferView { + GLenum indexType = GL_UNSIGNED_SHORT; + SizeT indexByteOffset = 0; + SizeT indexByteSize = 0; + }; + + struct DrawIndexedCmd { + GLenum mode = GL_TRIANGLES; + IndexBufferView indexBufferView; + + DrawIndexedCmdParam params; + }; + + struct MultiDrawIndexedCmd { + GLenum mode = GL_TRIANGLES; + IndexBufferView indexBufferView; + + Uint32 drawCount = 0; + DrawIndexedCmdParam* pParams = nullptr; }; struct QueueFamilyIndices { @@ -97,7 +109,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void Shutdown(); void SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags aspects, - GLenum indexType = 0, SizeT indexByteOffset = 0, Uint32 indexCount = 0); + const IndexBufferView* pIndexBufferView = nullptr); void ClearAttachmentsOnActiveRenderPass(VkCommandBuffer commandBuffer, const RenderPassEntry& compatibleRenderPassEntry); @@ -107,7 +119,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { GLbitfield mask, GLenum filter); void DrawArrays(const DrawCmd& payload); void DrawElements(const DrawIndexedCmd& payload); - void MultiDrawElements(const Vector& payloads); + void MultiDrawElements(const MultiDrawIndexedCmd& payloads); void Present(); const PhysicalDevice& GetPhysicalDevice() const; @@ -154,7 +166,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, Uint32 maxDrawCount, Uint32 stride); - PFNDrawIndexedIndirectCountFunc m_cmdDrawIndexedIndirectCount = nullptr; + static inline PFNDrawIndexedIndirectCountFunc s_vkCmdDrawIndexedIndirectCount = nullptr; VkCommandPool m_commandPool = VK_NULL_HANDLE; @@ -203,9 +215,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { 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); + const IndexBufferView* pIndexBufferView = nullptr); Bool InitializeBlitResources(); void ShutdownBlitResources(); Bool TryBlitToDefaultFramebufferWithShader(FrameContext::FrameData& frame,