diff --git a/CMakeLists.txt b/CMakeLists.txt index 42b733ec..99d3c4d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,7 +216,6 @@ set(SOURCE_FILES MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainManager.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineManager.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.cpp - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp MobileGL/MG_Backend/DirectVulkan/Managers/ProgramManager.cpp MobileGL/MG_State/GLState/Core.cpp diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp index b6898fb4..f80ab70d 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp @@ -8,8 +8,8 @@ #include "BackendObject_DirectVulkan.h" #include "MG_Backend/BackendObject.h" -#include -#include +#include "DirectVulkan.h" +#include "TmpImpl.h" #include namespace MobileGL::MG_Backend::DirectVulkan { diff --git a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h index c8805615..c4c11695 100644 --- a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h +++ b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h @@ -8,7 +8,6 @@ #pragma once #include -#include "Renderer/VulkanRenderer.h" namespace MobileGL::MG_Backend::DirectVulkan { namespace TmpImpl { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp deleted file mode 100644 index cb664880..00000000 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ /dev/null @@ -1,364 +0,0 @@ -// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp -// Copyright (c) 2025-2026 MobileGL-Dev -// Licensed under the GNU Lesser General Public License v3.0: -// https://www.gnu.org/licenses/gpl-3.0.txt -// https://www.gnu.org/licenses/lgpl-3.0.txt -// SPDX-License-Identifier: LGPL-3.0-only -// End of Source File Header - -#include "VulkanRenderer.h" - -namespace MobileGL::MG_Backend::DirectVulkan { - namespace { - VkShaderModule CreateShaderModule(VkDevice device, const Vector& spv) { - VkShaderModuleCreateInfo smci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - smci.codeSize = spv.size() * sizeof(Uint); - smci.pCode = spv.data(); - VkShaderModule module = VK_NULL_HANDLE; - VK_VERIFY(vkCreateShaderModule(device, &smci, nullptr, &module), "vkCreateShaderModule"); - return module; - } - } // namespace - - VulkanRenderer::VulkanRenderer(ANativeWindow* window) : m_window(window) {} - - VulkanRenderer::~VulkanRenderer() { - if (!m_initialized) return; - vkDeviceWaitIdle(m_ctx.GetDevice()); - DestroyPipelines(); - DestroyFrameResources(); - DestroyRenderPass(); - if (m_commandPool != VK_NULL_HANDLE) { - vkDestroyCommandPool(m_ctx.GetDevice(), m_commandPool, nullptr); - m_commandPool = VK_NULL_HANDLE; - } - if (m_swapchain) { - m_swapchain.reset(); - } - m_ctx.Cleanup(); - m_initialized = false; - } - - void VulkanRenderer::Initialize() { - if (m_initialized) return; - m_ctx.Initialize(m_window, "MobileGL-VulkanRenderer"); - m_swapchain = MakeUnique(m_ctx); - m_swapchain->Initialize(); - CreateCommandPool(); - CreateRenderPass(); - CreateFramebuffers(); - CreateFrameResources(); - m_initialized = true; - } - - void VulkanRenderer::EnsureInitialized() { - if (!m_initialized) { - throw RuntimeError("VulkanRenderer not initialized"); - } - } - - void VulkanRenderer::CreateCommandPool() { - if (m_commandPool != VK_NULL_HANDLE) return; - VkCommandPoolCreateInfo cpci{VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; - cpci.queueFamilyIndex = m_ctx.GetGraphicsQueueFamily(); - cpci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - VK_VERIFY(vkCreateCommandPool(m_ctx.GetDevice(), &cpci, nullptr, &m_commandPool), "vkCreateCommandPool"); - } - - void VulkanRenderer::CreateRenderPass() { - DestroyRenderPass(); - VkAttachmentDescription color{}; - color.format = m_swapchain->GetFormat(); - color.samples = VK_SAMPLE_COUNT_1_BIT; - color.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - color.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription sub{}; - sub.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - sub.colorAttachmentCount = 1; - sub.pColorAttachments = &colorRef; - - VkSubpassDependency dep{}; - dep.srcSubpass = VK_SUBPASS_EXTERNAL; - dep.dstSubpass = 0; - dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - VkRenderPassCreateInfo rpci{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; - rpci.attachmentCount = 1; - rpci.pAttachments = &color; - rpci.subpassCount = 1; - rpci.pSubpasses = ⊂ - rpci.dependencyCount = 1; - rpci.pDependencies = &dep; - - VK_VERIFY(vkCreateRenderPass(m_ctx.GetDevice(), &rpci, nullptr, &m_renderPass), "vkCreateRenderPass"); - } - - void VulkanRenderer::DestroyRenderPass() { - if (m_renderPass != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_ctx.GetDevice(), m_renderPass, nullptr); - m_renderPass = VK_NULL_HANDLE; - } - } - - void VulkanRenderer::CreateFramebuffers() { - const auto& views = m_swapchain->GetImageViews(); - Vector fbs; - fbs.reserve(views.size()); - for (auto view : views) { - VkFramebufferCreateInfo fbci{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - fbci.renderPass = m_renderPass; - fbci.attachmentCount = 1; - fbci.pAttachments = &view; - fbci.width = m_swapchain->GetExtent().width; - fbci.height = m_swapchain->GetExtent().height; - fbci.layers = 1; - VkFramebuffer fb = VK_NULL_HANDLE; - VK_VERIFY(vkCreateFramebuffer(m_ctx.GetDevice(), &fbci, nullptr, &fb), "vkCreateFramebuffer"); - fbs.push_back(fb); - } - m_swapchain->SetFramebuffers(Move(fbs)); - } - - void VulkanRenderer::SetSwapchainViewportSize(const UintVec2& size) { - if (m_swapchain) m_swapchain->SetViewportSize(size); - } - - void VulkanRenderer::CreateFrameResources() { - DestroyFrameResources(); - Uint32 imageCount = static_cast(m_swapchain->GetImageViews().size()); - if (imageCount == 0) throw RuntimeError("Swapchain has zero images"); - Uint32 frames = std::min(2, imageCount); - for (Uint32 i = 0; i < frames; ++i) { - auto frame = MakeUnique(); - frame->Initialize(m_ctx, m_commandPool); - m_frames.push_back(Move(frame)); - } - m_currentFrame = 0; - } - - void VulkanRenderer::DestroyFrameResources() { - for (auto& frame : m_frames) { - if (frame) frame->Cleanup(m_ctx); - } - m_frames.clear(); - } - - void VulkanRenderer::DestroyPipelines() { - auto device = m_ctx.GetDevice(); - for (auto& [_, info] : m_pipelines) { - if (info.pipeline != VK_NULL_HANDLE) vkDestroyPipeline(device, info.pipeline, nullptr); - if (info.layout != VK_NULL_HANDLE) vkDestroyPipelineLayout(device, info.layout, nullptr); - } - m_pipelines.clear(); - } - - VkPipeline VulkanRenderer::CreateGraphicsPipelineFromSpv(const String& name, const Vector& vertexSpv, - const Vector& fragmentSpv) { - EnsureInitialized(); - auto it = m_pipelines.find(name); - if (it != m_pipelines.end()) return it->second.pipeline; - - VkShaderModule vs = CreateShaderModule(m_ctx.GetDevice(), vertexSpv); - VkShaderModule fs = CreateShaderModule(m_ctx.GetDevice(), fragmentSpv); - - VkPipelineShaderStageCreateInfo stages[2] = {}; - stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - stages[0].module = vs; - stages[0].pName = "main"; - stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - stages[1].module = fs; - stages[1].pName = "main"; - - VkPipelineVertexInputStateCreateInfo vertexInput{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; - - VkPipelineInputAssemblyStateCreateInfo ia{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; - ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - ia.primitiveRestartEnable = VK_FALSE; - - VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; - vpci.viewportCount = 1; - vpci.scissorCount = 1; - - VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; - raster.polygonMode = VK_POLYGON_MODE_FILL; - raster.cullMode = VK_CULL_MODE_NONE; - raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - raster.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; - ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - VkPipelineColorBlendAttachmentState colorAttach{}; - colorAttach.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorAttach.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; - blend.attachmentCount = 1; - blend.pAttachments = &colorAttach; - - VkDynamicState dynamics[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; - VkPipelineDynamicStateCreateInfo dyn{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; - dyn.dynamicStateCount = 2; - dyn.pDynamicStates = dynamics; - - VkPipelineLayoutCreateInfo plci{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - VkPipelineLayout layout = VK_NULL_HANDLE; - VK_VERIFY(vkCreatePipelineLayout(m_ctx.GetDevice(), &plci, nullptr, &layout), "vkCreatePipelineLayout"); - - VkGraphicsPipelineCreateInfo gpi{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; - gpi.stageCount = 2; - gpi.pStages = stages; - gpi.pVertexInputState = &vertexInput; - gpi.pInputAssemblyState = &ia; - gpi.pViewportState = &vpci; - gpi.pRasterizationState = &raster; - gpi.pMultisampleState = &ms; - gpi.pColorBlendState = &blend; - gpi.pDynamicState = &dyn; - gpi.layout = layout; - gpi.renderPass = m_renderPass; - gpi.subpass = 0; - - VkPipeline pipeline = VK_NULL_HANDLE; - VK_VERIFY(vkCreateGraphicsPipelines(m_ctx.GetDevice(), VK_NULL_HANDLE, 1, &gpi, nullptr, &pipeline), - "vkCreateGraphicsPipelines"); - - vkDestroyShaderModule(m_ctx.GetDevice(), vs, nullptr); - vkDestroyShaderModule(m_ctx.GetDevice(), fs, nullptr); - - m_pipelines[name] = {pipeline, layout}; - return pipeline; - } - - void VulkanRenderer::RegisterRenderCallback(const String& name, RenderCallback callback) { - m_callbacks[name] = Move(callback); - } - - void VulkanRenderer::RecordAndSubmit(Uint32 imageIndex) { - auto& frame = *m_frames[m_currentFrame]; - VK_VERIFY(vkWaitForFences(m_ctx.GetDevice(), 1, &frame.InFlightFence, VK_TRUE, UINT64_MAX), "vkWaitForFences"); - VK_VERIFY(vkResetFences(m_ctx.GetDevice(), 1, &frame.InFlightFence), "vkResetFences"); - VK_VERIFY(vkResetCommandBuffer(frame.CommandBuffer, 0), "vkResetCommandBuffer"); - - VkCommandBufferBeginInfo bi{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - VK_VERIFY(vkBeginCommandBuffer(frame.CommandBuffer, &bi), "vkBeginCommandBuffer"); - - VkClearValue clear{}; - clear.color = {{0.0f, 0.0f, 0.0f, 1.0f}}; - - VkRenderPassBeginInfo rpbi{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - rpbi.renderPass = m_renderPass; - rpbi.framebuffer = m_swapchain->GetFramebuffers()[imageIndex]; - rpbi.renderArea.offset = {0, 0}; - rpbi.renderArea.extent = m_swapchain->GetExtent(); - rpbi.clearValueCount = 1; - rpbi.pClearValues = &clear; - - vkCmdBeginRenderPass(frame.CommandBuffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE); - - VkViewport vp{}; - vp.x = 0.0f; - vp.y = 0.0f; - vp.width = static_cast(m_swapchain->GetExtent().width); - vp.height = static_cast(m_swapchain->GetExtent().height); - vp.minDepth = 0.0f; - vp.maxDepth = 1.0f; - vkCmdSetViewport(frame.CommandBuffer, 0, 1, &vp); - - VkRect2D scissor{{0, 0}, m_swapchain->GetExtent()}; - vkCmdSetScissor(frame.CommandBuffer, 0, 1, &scissor); - - for (auto& [_, cb] : m_callbacks) { - cb(frame.CommandBuffer, imageIndex, m_swapchain->GetExtent()); - } - - vkCmdEndRenderPass(frame.CommandBuffer); - VK_VERIFY(vkEndCommandBuffer(frame.CommandBuffer), "vkEndCommandBuffer"); - - VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; - VkSemaphore waitSemaphores[] = {frame.ImageAvailable}; - VkSemaphore signalSemaphores[] = {frame.RenderFinished}; - - VkSubmitInfo si{VK_STRUCTURE_TYPE_SUBMIT_INFO}; - si.waitSemaphoreCount = 1; - si.pWaitSemaphores = waitSemaphores; - si.pWaitDstStageMask = waitStages; - si.commandBufferCount = 1; - si.pCommandBuffers = &frame.CommandBuffer; - si.signalSemaphoreCount = 1; - si.pSignalSemaphores = signalSemaphores; - - VK_VERIFY(vkQueueSubmit(m_ctx.GetGraphicsQueue(), 1, &si, frame.InFlightFence), "vkQueueSubmit"); - } - - void VulkanRenderer::DrawAndPresent() { - EnsureInitialized(); - auto& frame = *m_frames[m_currentFrame]; - auto& imagesInFlight = m_swapchain->GetImagesInFlight(); - - Uint32 imageIndex = 0; - VkResult res = vkAcquireNextImageKHR(m_ctx.GetDevice(), m_swapchain->GetSwapchain(), UINT64_MAX, - frame.ImageAvailable, VK_NULL_HANDLE, &imageIndex); - if (res == VK_ERROR_OUT_OF_DATE_KHR) { - RecreateSwapchain(); - return; - } - VK_VERIFY(res, "vkAcquireNextImageKHR"); - - if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { - vkWaitForFences(m_ctx.GetDevice(), 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX); - } - imagesInFlight[imageIndex] = frame.InFlightFence; - - RecordAndSubmit(imageIndex); - - VkPresentInfoKHR pi{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; - VkSemaphore waitSemaphores[] = {frame.RenderFinished}; - pi.waitSemaphoreCount = 1; - pi.pWaitSemaphores = waitSemaphores; - VkSwapchainKHR swapchains[] = {m_swapchain->GetSwapchain()}; - pi.swapchainCount = 1; - pi.pSwapchains = swapchains; - pi.pImageIndices = &imageIndex; - - VkResult pres = vkQueuePresentKHR(m_ctx.GetGraphicsQueue(), &pi); - if (pres == VK_ERROR_OUT_OF_DATE_KHR || pres == VK_SUBOPTIMAL_KHR) { - RecreateSwapchain(); - } else { - VK_VERIFY(pres, "vkQueuePresentKHR"); - } - - m_currentFrame = (m_currentFrame + 1) % m_frames.size(); - } - - void VulkanRenderer::RecreateSwapchain() { - vkDeviceWaitIdle(m_ctx.GetDevice()); - DestroyFrameResources(); - DestroyRenderPass(); - - m_swapchain->Recreate(); - CreateRenderPass(); - CreateFramebuffers(); - CreateFrameResources(); - - DestroyPipelines(); - } - - void VulkanRenderer::RenderFrame() { - DrawAndPresent(); - } - - void VulkanRenderer::Present() { - DrawAndPresent(); - } -} // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h deleted file mode 100644 index f2534054..00000000 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ /dev/null @@ -1,66 +0,0 @@ -// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h -// Copyright (c) 2025-2026 MobileGL-Dev -// Licensed under the GNU Lesser General Public License v3.0: -// https://www.gnu.org/licenses/gpl-3.0.txt -// https://www.gnu.org/licenses/lgpl-3.0.txt -// SPDX-License-Identifier: LGPL-3.0-only -// End of Source File Header - -#pragma once -#include -#include "VulkanContext.h" -#include "SwapchainManager.h" -#include "FrameContext.h" -#include "VkCommon.h" - -namespace MobileGL::MG_Backend::DirectVulkan { - class VulkanRenderer { - public: - using RenderCallback = std::function; - - explicit VulkanRenderer(ANativeWindow* window); - ~VulkanRenderer(); - - VulkanRenderer(const VulkanRenderer&) = delete; - VulkanRenderer& operator=(const VulkanRenderer&) = delete; - - void Initialize(); - void RenderFrame(); - void Present(); - void SetSwapchainViewportSize(const UintVec2& size); - - VkPipeline CreateGraphicsPipelineFromSpv(const String& name, const Vector& vertexSpv, - const Vector& fragmentSpv); - void RegisterRenderCallback(const String& name, RenderCallback callback); - - private: - void EnsureInitialized(); - void CreateCommandPool(); - void CreateRenderPass(); - void DestroyRenderPass(); - void CreateFramebuffers(); - void CreateFrameResources(); - void DestroyFrameResources(); - void RecreateSwapchain(); - void RecordAndSubmit(Uint32 imageIndex); - void DrawAndPresent(); - void DestroyPipelines(); - - struct PipelineInfo { - VkPipeline pipeline = VK_NULL_HANDLE; - VkPipelineLayout layout = VK_NULL_HANDLE; - }; - - ANativeWindow* m_window = nullptr; - VkManager::VulkanContext m_ctx; - UniquePtr m_swapchain; - VkRenderPass m_renderPass = VK_NULL_HANDLE; - VkCommandPool m_commandPool = VK_NULL_HANDLE; - Vector> m_frames; - Uint32 m_currentFrame = 0; - Bool m_initialized = false; - - UnorderedMap m_callbacks; - UnorderedMap m_pipelines; - }; -} // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/TmpImpl.cpp b/MobileGL/MG_Backend/DirectVulkan/TmpImpl.cpp index b7c2e688..854dcf71 100644 --- a/MobileGL/MG_Backend/DirectVulkan/TmpImpl.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/TmpImpl.cpp @@ -7,7 +7,7 @@ // End of Source File Header #include "TmpImpl.h" -#include "MG_Backend/DirectVulkan/DirectVulkan.h" + #include #include #include "MG_Util/Debug/Log.h"