mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 20:28:32 +09:00
[Feat] (MG_Backend/DirectVulkan): get rid of stuff that no longer needed
This commit is contained in:
+3
-7
@@ -208,14 +208,10 @@ set(SOURCE_FILES
|
||||
MobileGL/MG_Backend/DirectGLES/Managers.cpp
|
||||
|
||||
MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanContext.cpp
|
||||
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_Backend/DirectVulkan/Managers/VertexInputStateManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Managers/RenderStateManager.cpp
|
||||
# MobileGL/MG_Backend/DirectVulkan/Managers/ProgramManager.cpp
|
||||
# MobileGL/MG_Backend/DirectVulkan/Managers/VertexInputStateManager.cpp
|
||||
# MobileGL/MG_Backend/DirectVulkan/Managers/RenderStateManager.cpp
|
||||
|
||||
MobileGL/MG_State/GLState/Core.cpp
|
||||
MobileGL/MG_State/GLState/ErrorState/Error.cpp
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "ProgramManager.h"
|
||||
#include "MG_Backend/DirectVulkan/Renderer/VulkanContext.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
ProgramManager::ProgramManager(VulkanContext &ctx): m_ctx(ctx) {}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.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 "FrameContext.h"
|
||||
#include "VulkanContext.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
FrameContext::~FrameContext() = default;
|
||||
|
||||
void FrameContext::Initialize(VulkanContext& ctx, VkCommandPool pool) {
|
||||
// allocate cmd
|
||||
VkCommandBufferAllocateInfo abci{VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO};
|
||||
abci.commandPool = pool;
|
||||
abci.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
abci.commandBufferCount = 1;
|
||||
VK_VERIFY(vkAllocateCommandBuffers(ctx.GetDevice(), &abci, &CommandBuffer), "vkAllocateCommandBuffers");
|
||||
|
||||
// semaphores
|
||||
VkSemaphoreCreateInfo sci{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||
VK_VERIFY(vkCreateSemaphore(ctx.GetDevice(), &sci, nullptr, &ImageAvailable),
|
||||
"vkCreateSemaphore ImageAvailable");
|
||||
VK_VERIFY(vkCreateSemaphore(ctx.GetDevice(), &sci, nullptr, &RenderFinished),
|
||||
"vkCreateSemaphore RenderFinished");
|
||||
|
||||
// fence (start signaled)
|
||||
VkFenceCreateInfo fci{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
|
||||
fci.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
VK_VERIFY(vkCreateFence(ctx.GetDevice(), &fci, nullptr, &InFlightFence), "vkCreateFence");
|
||||
}
|
||||
|
||||
void FrameContext::Cleanup(VulkanContext& ctx) {
|
||||
if (ImageAvailable != VK_NULL_HANDLE) {
|
||||
vkDestroySemaphore(ctx.GetDevice(), ImageAvailable, nullptr);
|
||||
ImageAvailable = VK_NULL_HANDLE;
|
||||
}
|
||||
if (RenderFinished != VK_NULL_HANDLE) {
|
||||
vkDestroySemaphore(ctx.GetDevice(), RenderFinished, nullptr);
|
||||
RenderFinished = VK_NULL_HANDLE;
|
||||
}
|
||||
if (InFlightFence != VK_NULL_HANDLE) {
|
||||
vkDestroyFence(ctx.GetDevice(), InFlightFence, nullptr);
|
||||
InFlightFence = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
CommandBuffer = VK_NULL_HANDLE;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,28 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.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 <Includes.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VulkanContext;
|
||||
|
||||
struct FrameContext {
|
||||
FrameContext() = default;
|
||||
~FrameContext();
|
||||
|
||||
void Initialize(VulkanContext& ctx, VkCommandPool pool);
|
||||
void Cleanup(VulkanContext& ctx);
|
||||
|
||||
VkCommandBuffer CommandBuffer = VK_NULL_HANDLE;
|
||||
VkSemaphore ImageAvailable = VK_NULL_HANDLE;
|
||||
VkSemaphore RenderFinished = VK_NULL_HANDLE;
|
||||
VkFence InFlightFence = VK_NULL_HANDLE;
|
||||
Uint32 CurrentImageIndex = 0;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,141 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineManager.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 "PipelineManager.h"
|
||||
#include "VulkanContext.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
PipelineManager::PipelineManager(VulkanContext& ctx) : Ctx(ctx) {}
|
||||
PipelineManager::~PipelineManager() {
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void PipelineManager::EnsurePipelineLayout() {
|
||||
if (PipelineLayout != VK_NULL_HANDLE) return;
|
||||
VkPipelineLayoutCreateInfo plci{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
VK_VERIFY(vkCreatePipelineLayout(Ctx.GetDevice(), &plci, nullptr, &PipelineLayout), "vkCreatePipelineLayout");
|
||||
}
|
||||
|
||||
VkPipeline PipelineManager::CreateGraphicsPipelineFromSpv(const std::string& key,
|
||||
const std::vector<uint32_t>& vsSpv,
|
||||
const std::vector<uint32_t>& fsSpv,
|
||||
VkRenderPass renderPass, VkExtent2D extent) {
|
||||
if (Pipelines.find(key) != Pipelines.end()) {
|
||||
MGLOG_W("Pipeline key '%s' already exists - returning existing", key.c_str());
|
||||
return Pipelines[key];
|
||||
}
|
||||
EnsurePipelineLayout();
|
||||
|
||||
VkShaderModuleCreateInfo smci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
|
||||
smci.codeSize = vsSpv.size() * sizeof(uint32_t);
|
||||
smci.pCode = vsSpv.data();
|
||||
VkShaderModule vs;
|
||||
VK_VERIFY(vkCreateShaderModule(Ctx.GetDevice(), &smci, nullptr, &vs), "vkCreateShaderModule VS");
|
||||
|
||||
smci.codeSize = fsSpv.size() * sizeof(uint32_t);
|
||||
smci.pCode = fsSpv.data();
|
||||
VkShaderModule fs;
|
||||
VK_VERIFY(vkCreateShaderModule(Ctx.GetDevice(), &smci, nullptr, &fs), "vkCreateShaderModule FS");
|
||||
|
||||
VkPipelineShaderStageCreateInfo stages[2]{};
|
||||
stages[0] = {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] = {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};
|
||||
vertexInput.vertexBindingDescriptionCount = 0;
|
||||
vertexInput.vertexAttributeDescriptionCount = 0;
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo ia{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
|
||||
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
VkViewport vp{};
|
||||
vp.x = 0;
|
||||
vp.y = 0;
|
||||
vp.width = (float)extent.width;
|
||||
vp.height = (float)extent.height;
|
||||
vp.minDepth = 0;
|
||||
vp.maxDepth = 1;
|
||||
VkRect2D scissor{{0, 0}, extent};
|
||||
VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
|
||||
vpci.viewportCount = 1;
|
||||
vpci.pViewports = &vp;
|
||||
vpci.scissorCount = 1;
|
||||
vpci.pScissors = &scissor;
|
||||
|
||||
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_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;
|
||||
|
||||
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.layout = PipelineLayout;
|
||||
gpi.renderPass = renderPass;
|
||||
gpi.subpass = 0;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VK_VERIFY(vkCreateGraphicsPipelines(Ctx.GetDevice(), VK_NULL_HANDLE, 1, &gpi, nullptr, &pipeline),
|
||||
"vkCreateGraphicsPipelines");
|
||||
|
||||
vkDestroyShaderModule(Ctx.GetDevice(), vs, nullptr);
|
||||
vkDestroyShaderModule(Ctx.GetDevice(), fs, nullptr);
|
||||
|
||||
Pipelines.emplace(key, pipeline);
|
||||
MGLOG_D("Pipeline '%s' created", key.c_str());
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
VkPipeline PipelineManager::GetPipeline(const std::string& key) const {
|
||||
auto it = Pipelines.find(key);
|
||||
if (it == Pipelines.end()) return VK_NULL_HANDLE;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void PipelineManager::DestroyPipeline(const std::string& key) {
|
||||
auto it = Pipelines.find(key);
|
||||
if (it != Pipelines.end()) {
|
||||
vkDestroyPipeline(Ctx.GetDevice(), it->second, nullptr);
|
||||
Pipelines.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void PipelineManager::Cleanup() {
|
||||
for (auto& kv : Pipelines)
|
||||
vkDestroyPipeline(Ctx.GetDevice(), kv.second, nullptr);
|
||||
Pipelines.clear();
|
||||
if (PipelineLayout != VK_NULL_HANDLE) {
|
||||
vkDestroyPipelineLayout(Ctx.GetDevice(), PipelineLayout, nullptr);
|
||||
PipelineLayout = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,35 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineManager.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 <Includes.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VulkanContext;
|
||||
|
||||
class PipelineManager {
|
||||
public:
|
||||
PipelineManager(VulkanContext& ctx);
|
||||
~PipelineManager();
|
||||
|
||||
VkPipeline CreateGraphicsPipelineFromSpv(const std::string& key, const std::vector<uint32_t>& vsSpv,
|
||||
const std::vector<uint32_t>& fsSpv, VkRenderPass renderPass,
|
||||
VkExtent2D extent);
|
||||
|
||||
VkPipeline GetPipeline(const std::string& key) const;
|
||||
void DestroyPipeline(const std::string& key);
|
||||
void Cleanup();
|
||||
|
||||
private:
|
||||
VulkanContext& Ctx;
|
||||
VkPipelineLayout PipelineLayout = VK_NULL_HANDLE; // TODO: per-pipeline layouts?
|
||||
std::unordered_map<std::string, VkPipeline> Pipelines;
|
||||
|
||||
void EnsurePipelineLayout();
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,133 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainManager.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 "SwapchainManager.h"
|
||||
#include "VulkanContext.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
SwapchainManager::SwapchainManager(VulkanContext& ctx) : Ctx(ctx) {}
|
||||
SwapchainManager::~SwapchainManager() {
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void SwapchainManager::Initialize() {
|
||||
CreateSwapchainInternal();
|
||||
CreateImageViews();
|
||||
ImagesInFlight.resize(Images.size(), VK_NULL_HANDLE);
|
||||
}
|
||||
|
||||
void SwapchainManager::Recreate() {
|
||||
DestroyImageViews();
|
||||
if (Swapchain != VK_NULL_HANDLE) {
|
||||
vkDestroySwapchainKHR(Ctx.GetDevice(), Swapchain, nullptr);
|
||||
Swapchain = VK_NULL_HANDLE;
|
||||
}
|
||||
CreateSwapchainInternal();
|
||||
CreateImageViews();
|
||||
ImagesInFlight.resize(Images.size(), VK_NULL_HANDLE);
|
||||
|
||||
Framebuffers.clear();
|
||||
MGLOG_D("Swapchain recreated");
|
||||
}
|
||||
|
||||
void SwapchainManager::Cleanup() {
|
||||
for (auto fb : Framebuffers)
|
||||
if (fb != VK_NULL_HANDLE) vkDestroyFramebuffer(Ctx.GetDevice(), fb, nullptr);
|
||||
Framebuffers.clear();
|
||||
DestroyImageViews();
|
||||
if (Swapchain != VK_NULL_HANDLE) {
|
||||
vkDestroySwapchainKHR(Ctx.GetDevice(), Swapchain, nullptr);
|
||||
Swapchain = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void SwapchainManager::SetFramebuffers(std::vector<VkFramebuffer>&& fbs) {
|
||||
Framebuffers = std::move(fbs);
|
||||
}
|
||||
|
||||
VkPresentModeKHR SwapchainManager::QueryPossiblePresentMode() {
|
||||
const auto& surface = Ctx.GetSurface();
|
||||
const auto& phys = Ctx.GetPhysicalDevice();
|
||||
Uint32 modeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(phys, surface, &modeCount, NULL);
|
||||
|
||||
Vector<VkPresentModeKHR> modes(modeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(phys, surface, &modeCount, modes.data());
|
||||
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
|
||||
for (auto m : modes) {
|
||||
if (m == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||
presentMode = m;
|
||||
break;
|
||||
}
|
||||
if (m == VK_PRESENT_MODE_IMMEDIATE_KHR) {
|
||||
presentMode = m;
|
||||
}
|
||||
}
|
||||
|
||||
return presentMode;
|
||||
}
|
||||
|
||||
void SwapchainManager::CreateSwapchainInternal() {
|
||||
VkSurfaceCapabilitiesKHR caps;
|
||||
VK_VERIFY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Ctx.GetPhysicalDevice(), Ctx.GetSurface(), &caps),
|
||||
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
|
||||
|
||||
Extent = caps.currentExtent;
|
||||
ImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
VkSwapchainCreateInfoKHR sci{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
|
||||
sci.surface = Ctx.GetSurface();
|
||||
sci.minImageCount = std::max<uint32_t>(2, caps.minImageCount);
|
||||
sci.imageFormat = ImageFormat;
|
||||
sci.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
sci.imageExtent = Extent;
|
||||
sci.imageArrayLayers = 1;
|
||||
sci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
sci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
sci.preTransform = caps.currentTransform;
|
||||
sci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
sci.presentMode = QueryPossiblePresentMode();
|
||||
|
||||
VK_VERIFY(vkCreateSwapchainKHR(Ctx.GetDevice(), &sci, nullptr, &Swapchain), "vkCreateSwapchainKHR");
|
||||
|
||||
uint32_t count = 0;
|
||||
VK_VERIFY(vkGetSwapchainImagesKHR(Ctx.GetDevice(), Swapchain, &count, nullptr),
|
||||
"vkGetSwapchainImagesKHR count");
|
||||
Images.resize(count);
|
||||
VK_VERIFY(vkGetSwapchainImagesKHR(Ctx.GetDevice(), Swapchain, &count, Images.data()),
|
||||
"vkGetSwapchainImagesKHR images");
|
||||
MGLOG_D("Swapchain created (%u images)", count);
|
||||
}
|
||||
|
||||
void SwapchainManager::CreateImageViews() {
|
||||
DestroyImageViews();
|
||||
ImageViews.resize(Images.size());
|
||||
for (size_t i = 0; i < Images.size(); ++i) {
|
||||
VkImageViewCreateInfo ivci{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||
ivci.image = Images[i];
|
||||
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
ivci.format = ImageFormat;
|
||||
ivci.components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
|
||||
VK_COMPONENT_SWIZZLE_A};
|
||||
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
ivci.subresourceRange.baseMipLevel = 0;
|
||||
ivci.subresourceRange.levelCount = 1;
|
||||
ivci.subresourceRange.baseArrayLayer = 0;
|
||||
ivci.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(Ctx.GetDevice(), &ivci, nullptr, &ImageViews[i]), "vkCreateImageView");
|
||||
}
|
||||
MGLOG_D("ImageViews created");
|
||||
}
|
||||
|
||||
void SwapchainManager::DestroyImageViews() {
|
||||
for (auto iv : ImageViews)
|
||||
if (iv != VK_NULL_HANDLE) vkDestroyImageView(Ctx.GetDevice(), iv, nullptr);
|
||||
ImageViews.clear();
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,49 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainManager.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 <Includes.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VulkanContext;
|
||||
|
||||
class SwapchainManager {
|
||||
public:
|
||||
SwapchainManager(VulkanContext& ctx);
|
||||
~SwapchainManager();
|
||||
|
||||
void Initialize();
|
||||
void Recreate();
|
||||
void Cleanup();
|
||||
|
||||
VkSwapchainKHR GetSwapchain() const { return Swapchain; }
|
||||
VkFormat GetFormat() const { return ImageFormat; }
|
||||
VkExtent2D GetExtent() const { return Extent; }
|
||||
const std::vector<VkImageView>& GetImageViews() const { return ImageViews; }
|
||||
const std::vector<VkFramebuffer>& GetFramebuffers() const { return Framebuffers; }
|
||||
const std::vector<VkImage>& GetImages() const { return Images; }
|
||||
std::vector<VkFence>& GetImagesInFlight() { return ImagesInFlight; }
|
||||
|
||||
void SetFramebuffers(std::vector<VkFramebuffer>&& fbs);
|
||||
|
||||
private:
|
||||
VulkanContext& Ctx;
|
||||
VkSwapchainKHR Swapchain = VK_NULL_HANDLE;
|
||||
VkFormat ImageFormat = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D Extent{0, 0};
|
||||
std::vector<VkImage> Images;
|
||||
std::vector<VkImageView> ImageViews;
|
||||
std::vector<VkFence> ImagesInFlight;
|
||||
std::vector<VkFramebuffer> Framebuffers;
|
||||
|
||||
void CreateSwapchainInternal();
|
||||
void CreateImageViews();
|
||||
void DestroyImageViews();
|
||||
VkPresentModeKHR QueryPossiblePresentMode();
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,141 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanContext.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 "VulkanContext.h"
|
||||
#include "MG_Util/Types.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VulkanContext::~VulkanContext() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void VulkanContext::Initialize(NativeWindowType window, const std::string& appName) {
|
||||
if (Initialized) return;
|
||||
CreateInstance(appName);
|
||||
CreateSurface(window);
|
||||
PickPhysicalDevice();
|
||||
CreateLogicalDevice();
|
||||
Initialized = true;
|
||||
MGLOG_D("VulkanContext initialized");
|
||||
}
|
||||
|
||||
void VulkanContext::Shutdown() {
|
||||
if (!Initialized && Instance == VK_NULL_HANDLE) return;
|
||||
if (Device != VK_NULL_HANDLE) {
|
||||
vkDeviceWaitIdle(Device);
|
||||
vkDestroyDevice(Device, nullptr);
|
||||
Device = VK_NULL_HANDLE;
|
||||
}
|
||||
if (Surface != VK_NULL_HANDLE) {
|
||||
vkDestroySurfaceKHR(Instance, Surface, nullptr);
|
||||
Surface = VK_NULL_HANDLE;
|
||||
}
|
||||
if (Instance != VK_NULL_HANDLE) {
|
||||
vkDestroyInstance(Instance, nullptr);
|
||||
Instance = VK_NULL_HANDLE;
|
||||
}
|
||||
Initialized = false;
|
||||
MGLOG_D("VulkanContext shutdown");
|
||||
}
|
||||
|
||||
void VulkanContext::CreateInstance(const std::string& appName) {
|
||||
VkApplicationInfo appInfo{VK_STRUCTURE_TYPE_APPLICATION_INFO};
|
||||
appInfo.pApplicationName = appName.c_str();
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
appInfo.apiVersion = VK_API_VERSION_1_3;
|
||||
#else
|
||||
appInfo.apiVersion = VK_API_VERSION_1_1;
|
||||
#endif
|
||||
|
||||
const char* exts[] = {VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
|
||||
#elif defined VK_USE_PLATFORM_WIN32_KHR
|
||||
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
|
||||
#else
|
||||
#warning "VulkanContext::CreateInstance: VK_KHR_*_surface extension not defined on this platform"
|
||||
#endif
|
||||
}; // TODO: support more platforms
|
||||
|
||||
VkInstanceCreateInfo ci{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
|
||||
ci.pApplicationInfo = &appInfo;
|
||||
ci.enabledExtensionCount = 2;
|
||||
ci.ppEnabledExtensionNames = exts;
|
||||
|
||||
VK_VERIFY(vkCreateInstance(&ci, nullptr, &Instance), "vkCreateInstance failed");
|
||||
}
|
||||
|
||||
void VulkanContext::CreateSurface(NativeWindowType window) {
|
||||
if (!Instance) throw RuntimeError("Instance not created");
|
||||
#if defined VK_USE_PLATFORM_ANDROID_KHR
|
||||
auto* nativeWindow = static_cast<ANativeWindow*>(window);
|
||||
if (!nativeWindow) throw RuntimeError("ANativeWindowType is null");
|
||||
|
||||
VkAndroidSurfaceCreateInfoKHR sci{VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR};
|
||||
sci.window = nativeWindow;
|
||||
VK_VERIFY(vkCreateAndroidSurfaceKHR(Instance, &sci, nullptr, &Surface), "vkCreateAndroidSurfaceKHR failed");
|
||||
#elif defined VK_USE_PLATFORM_WIN32_KHR
|
||||
auto hwnd = static_cast<HWND>(window);
|
||||
MOBILEGL_ASSERT(hwnd, "HWND is null");
|
||||
|
||||
VkWin32SurfaceCreateInfoKHR sci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR};
|
||||
sci.hwnd = hwnd;
|
||||
VK_VERIFY(vkCreateWin32SurfaceKHR(Instance, &sci, nullptr, &Surface), "vkCreateWin32SurfaceKHR failed");
|
||||
#else
|
||||
//#warning "VulkanRenderer::Initialize called on a platform which is not supported yet"
|
||||
MGLOG_W("VulkanRenderer::Initialize called on a platform which is not supported yet"); // TODO: support more
|
||||
// platforms
|
||||
#endif
|
||||
}
|
||||
|
||||
void VulkanContext::PickPhysicalDevice() {
|
||||
uint32_t count = 0;
|
||||
VK_VERIFY(vkEnumeratePhysicalDevices(Instance, &count, nullptr), "vkEnumeratePhysicalDevices count");
|
||||
if (count == 0) throw RuntimeError("No physical devices");
|
||||
std::vector<VkPhysicalDevice> devs(count);
|
||||
VK_VERIFY(vkEnumeratePhysicalDevices(Instance, &count, devs.data()), "vkEnumeratePhysicalDevices");
|
||||
|
||||
for (auto d : devs) {
|
||||
uint32_t qcount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(d, &qcount, nullptr);
|
||||
std::vector<VkQueueFamilyProperties> qprops(qcount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(d, &qcount, qprops.data());
|
||||
for (uint32_t i = 0; i < qcount; ++i) {
|
||||
VkBool32 present = VK_FALSE;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(d, i, Surface, &present);
|
||||
if ((qprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && present) {
|
||||
PhysicalDevice = d;
|
||||
GraphicsQueueFamily = i;
|
||||
MGLOG_D("Picked physical device, queue family %u", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw RuntimeError("No suitable physical device");
|
||||
}
|
||||
|
||||
void VulkanContext::CreateLogicalDevice() {
|
||||
float prio = 1.0f;
|
||||
VkDeviceQueueCreateInfo dqci{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
|
||||
dqci.queueFamilyIndex = GraphicsQueueFamily;
|
||||
dqci.queueCount = 1;
|
||||
dqci.pQueuePriorities = &prio;
|
||||
|
||||
const char* devExts[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
|
||||
VkDeviceCreateInfo dci{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
|
||||
dci.queueCreateInfoCount = 1;
|
||||
dci.pQueueCreateInfos = &dqci;
|
||||
dci.enabledExtensionCount = 1;
|
||||
dci.ppEnabledExtensionNames = devExts;
|
||||
|
||||
VK_VERIFY(vkCreateDevice(PhysicalDevice, &dci, nullptr, &Device), "vkCreateDevice failed");
|
||||
vkGetDeviceQueue(Device, GraphicsQueueFamily, 0, &GraphicsQueue);
|
||||
MGLOG_D("Logical device created");
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,48 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanContext.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 <Includes.h>
|
||||
|
||||
#define VK_VERIFY(expr, ...) \
|
||||
do { \
|
||||
VkResult _vk_verify_result = (expr); \
|
||||
MOBILEGL_ASSERT(_vk_verify_result == VK_SUCCESS, "Vulkan error %d at %s:%d" __VA_OPT__(" - ") __VA_ARGS__, _vk_verify_result, __FILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VulkanContext {
|
||||
public:
|
||||
VulkanContext() = default;
|
||||
~VulkanContext();
|
||||
|
||||
void Initialize(NativeWindowType window, const std::string& appName = "MobileGL-VulkanRenderer");
|
||||
void Shutdown();
|
||||
|
||||
VkInstance GetInstance() const { return Instance; }
|
||||
VkPhysicalDevice GetPhysicalDevice() const { return PhysicalDevice; }
|
||||
VkDevice GetDevice() const { return Device; }
|
||||
VkQueue GetGraphicsQueue() const { return GraphicsQueue; }
|
||||
uint32_t GetGraphicsQueueFamily() const { return GraphicsQueueFamily; }
|
||||
VkSurfaceKHR GetSurface() const { return Surface; }
|
||||
|
||||
private:
|
||||
void CreateInstance(const std::string& appName);
|
||||
void CreateSurface(NativeWindowType window);
|
||||
void PickPhysicalDevice();
|
||||
void CreateLogicalDevice();
|
||||
|
||||
VkInstance Instance = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE;
|
||||
VkDevice Device = VK_NULL_HANDLE;
|
||||
VkQueue GraphicsQueue = VK_NULL_HANDLE;
|
||||
uint32_t GraphicsQueueFamily = UINT32_MAX;
|
||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||
bool Initialized = false;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -7,10 +7,6 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "VulkanRenderer.h"
|
||||
#include "VulkanContext.h"
|
||||
#include "SwapchainManager.h"
|
||||
#include "PipelineManager.h"
|
||||
#include "FrameContext.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkBool32 VulkanRenderer::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
|
||||
Reference in New Issue
Block a user