mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Feat] (MG_Backend/DirectVulkan): VkBufferManager
This commit is contained in:
@@ -225,6 +225,7 @@ set(SOURCE_FILES
|
|||||||
MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@
|
|||||||
#define MOBILEGL_EGL_API MOBILEGL_API
|
#define MOBILEGL_EGL_API MOBILEGL_API
|
||||||
|
|
||||||
// ====================== MobileGL configurations ======================= //
|
// ====================== MobileGL configurations ======================= //
|
||||||
#define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_INFO
|
#define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_DEBUG
|
||||||
|
|
||||||
#define MOBILEGL_LOG_ENABLE_CONSOLE 0
|
#define MOBILEGL_LOG_ENABLE_CONSOLE 0
|
||||||
#define MOBILEGL_LOG_ENABLE_FILE 1
|
#define MOBILEGL_LOG_ENABLE_FILE 1
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.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 "VkBufferManager.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
Bool VkBufferManager::Initialize(const VkBufferManagerInitInfo& initInfo) {
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(initInfo.allocator != nullptr, "VkBufferManager::Initialize requires valid allocator");
|
||||||
|
MOBILEGL_ASSERT(initInfo.frameCount > 0, "VkBufferManager::Initialize requires non-zero frame count");
|
||||||
|
|
||||||
|
m_initInfo = initInfo;
|
||||||
|
return InitializeTransientArenas();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::Shutdown() {
|
||||||
|
m_vertexUploadArena.Shutdown();
|
||||||
|
m_indexUploadArena.Shutdown();
|
||||||
|
m_initInfo = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferManager::RecreateTransientArenas(Uint32 frameCount) {
|
||||||
|
MOBILEGL_ASSERT(m_initInfo.allocator != nullptr, "VkBufferManager::RecreateTransientArenas requires initialized manager");
|
||||||
|
MOBILEGL_ASSERT(frameCount > 0, "VkBufferManager::RecreateTransientArenas requires non-zero frame count");
|
||||||
|
|
||||||
|
m_vertexUploadArena.Shutdown();
|
||||||
|
m_indexUploadArena.Shutdown();
|
||||||
|
m_initInfo.frameCount = frameCount;
|
||||||
|
return InitializeTransientArenas();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::BeginFrame(Uint32 frameIndex) {
|
||||||
|
m_vertexUploadArena.BeginFrame(frameIndex);
|
||||||
|
m_indexUploadArena.BeginFrame(frameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferManager::UploadTransient(TransientBufferKind kind, Uint32 frameIndex, const void* data,
|
||||||
|
VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice) {
|
||||||
|
switch (kind) {
|
||||||
|
case TransientBufferKind::Vertex:
|
||||||
|
return m_vertexUploadArena.Upload(frameIndex, data, size, alignment, outSlice);
|
||||||
|
case TransientBufferKind::Index:
|
||||||
|
return m_indexUploadArena.Upload(frameIndex, data, size, alignment, outSlice);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferManager::InitializeTransientArenas() {
|
||||||
|
Bool ok = m_vertexUploadArena.Initialize({
|
||||||
|
.allocator = m_initInfo.allocator,
|
||||||
|
.frameCount = m_initInfo.frameCount,
|
||||||
|
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
|
.memoryUsage = m_initInfo.transientMemoryUsage,
|
||||||
|
.allocationFlags = m_initInfo.transientAllocationFlags,
|
||||||
|
.minBufferSize = m_initInfo.minVertexUploadBytes,
|
||||||
|
.persistentlyMapped = m_initInfo.transientPersistentMapping,
|
||||||
|
});
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = m_indexUploadArena.Initialize({
|
||||||
|
.allocator = m_initInfo.allocator,
|
||||||
|
.frameCount = m_initInfo.frameCount,
|
||||||
|
.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||||
|
.memoryUsage = m_initInfo.transientMemoryUsage,
|
||||||
|
.allocationFlags = m_initInfo.transientAllocationFlags,
|
||||||
|
.minBufferSize = m_initInfo.minIndexUploadBytes,
|
||||||
|
.persistentlyMapped = m_initInfo.transientPersistentMapping,
|
||||||
|
});
|
||||||
|
if (!ok) {
|
||||||
|
m_vertexUploadArena.Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.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 "BufferArena.h"
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
enum class TransientBufferKind : Uint8 {
|
||||||
|
Vertex,
|
||||||
|
Index,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VkBufferManagerInitInfo {
|
||||||
|
VmaAllocator allocator = nullptr;
|
||||||
|
Uint32 frameCount = 0;
|
||||||
|
VkDeviceSize minVertexUploadBytes = 4 * 1024 * 1024;
|
||||||
|
VkDeviceSize minIndexUploadBytes = 1 * 1024 * 1024;
|
||||||
|
VmaMemoryUsage transientMemoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
VmaAllocationCreateFlags transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||||
|
Bool transientPersistentMapping = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VkBufferManager {
|
||||||
|
public:
|
||||||
|
Bool Initialize(const VkBufferManagerInitInfo& initInfo);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
// Recreate all per-frame transient arenas
|
||||||
|
Bool RecreateTransientArenas(Uint32 frameCount);
|
||||||
|
void BeginFrame(Uint32 frameIndex);
|
||||||
|
|
||||||
|
Bool UploadTransient(TransientBufferKind kind, Uint32 frameIndex, const void* data, VkDeviceSize size,
|
||||||
|
VkDeviceSize alignment, BufferSlice& outSlice);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Bool InitializeTransientArenas();
|
||||||
|
|
||||||
|
VkBufferManagerInitInfo m_initInfo{};
|
||||||
|
BufferArena m_vertexUploadArena;
|
||||||
|
BufferArena m_indexUploadArena;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -334,32 +334,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
MOBILEGL_ASSERT(m_vertexInputStateFactory != nullptr, "VertexInputStateFactory creation failed.");
|
MOBILEGL_ASSERT(m_vertexInputStateFactory != nullptr, "VertexInputStateFactory creation failed.");
|
||||||
|
|
||||||
CreateFrameContexts();
|
CreateFrameContexts();
|
||||||
succeeded = m_vertexUploadArena.Initialize({
|
succeeded = m_bufferManager.Initialize({
|
||||||
.allocator = m_allocator,
|
.allocator = m_allocator,
|
||||||
.frameCount = m_frameContext.GetFrameCount(),
|
.frameCount = m_frameContext.GetFrameCount(),
|
||||||
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
.minVertexUploadBytes = 4 * 1024 * 1024,
|
||||||
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
|
.minIndexUploadBytes = 1 * 1024 * 1024,
|
||||||
.allocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
.transientMemoryUsage = VMA_MEMORY_USAGE_AUTO,
|
||||||
.minBufferSize = 4 * 1024 * 1024,
|
.transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||||
.persistentlyMapped = false,
|
.transientPersistentMapping = false,
|
||||||
});
|
});
|
||||||
MOBILEGL_ASSERT(succeeded, "Vertex upload arena initialization failed.");
|
MOBILEGL_ASSERT(succeeded, "Buffer manager initialization failed.");
|
||||||
succeeded = m_indexUploadArena.Initialize({
|
|
||||||
.allocator = m_allocator,
|
|
||||||
.frameCount = m_frameContext.GetFrameCount(),
|
|
||||||
.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
||||||
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
|
|
||||||
.allocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
|
||||||
.minBufferSize = 1 * 1024 * 1024,
|
|
||||||
.persistentlyMapped = false,
|
|
||||||
});
|
|
||||||
MOBILEGL_ASSERT(succeeded, "Index upload arena initialization failed.");
|
|
||||||
|
|
||||||
// Prime the first frame so Render() always targets an acquired swapchain image.
|
// Prime the first frame so Render() always targets an acquired swapchain image.
|
||||||
VK_VERIFY(m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired),
|
VK_VERIFY(m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired),
|
||||||
"Initialize, WaitAndAcquireNextImage");
|
"Initialize, WaitAndAcquireNextImage");
|
||||||
m_vertexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||||
m_indexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
|
||||||
|
|
||||||
MGLOG_D("VulkanRenderer initialized");
|
MGLOG_D("VulkanRenderer initialized");
|
||||||
}
|
}
|
||||||
@@ -379,8 +368,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_textureManager.reset();
|
m_textureManager.reset();
|
||||||
}
|
}
|
||||||
m_vertexInputStateFactory.reset();
|
m_vertexInputStateFactory.reset();
|
||||||
m_vertexUploadArena.Shutdown();
|
m_bufferManager.Shutdown();
|
||||||
m_indexUploadArena.Shutdown();
|
|
||||||
|
|
||||||
m_frameContext.Destroy(m_device, m_commandPool);
|
m_frameContext.Destroy(m_device, m_commandPool);
|
||||||
|
|
||||||
@@ -459,8 +447,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
const SizeT sourceSize = sourceBuffer->GetSize();
|
const SizeT sourceSize = sourceBuffer->GetSize();
|
||||||
BufferSlice slice{};
|
BufferSlice slice{};
|
||||||
if (!m_vertexUploadArena.Upload(frameIndex, sourceData->data(), static_cast<VkDeviceSize>(sourceSize), 16,
|
if (!m_bufferManager.UploadTransient(TransientBufferKind::Vertex, frameIndex, sourceData->data(),
|
||||||
slice)) {
|
static_cast<VkDeviceSize>(sourceSize), 16, slice)) {
|
||||||
MGLOG_E("UploadAndBindVertexStreams skipped: failed to upload binding %zu", binding);
|
MGLOG_E("UploadAndBindVertexStreams skipped: failed to upload binding %zu", binding);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -501,7 +489,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const Uint32 frameIndex = m_frameContext.GetCurrentFrameIndex();
|
const Uint32 frameIndex = m_frameContext.GetCurrentFrameIndex();
|
||||||
const VkDeviceSize alignment = indexSize;
|
const VkDeviceSize alignment = indexSize;
|
||||||
BufferSlice slice{};
|
BufferSlice slice{};
|
||||||
if (!m_indexUploadArena.Upload(frameIndex, indexData->data() + pIndexBufferView->indexByteOffset,
|
if (!m_bufferManager.UploadTransient(TransientBufferKind::Index, frameIndex,
|
||||||
|
indexData->data() + pIndexBufferView->indexByteOffset,
|
||||||
static_cast<VkDeviceSize>(indexDataSizeBytes), alignment, slice)) {
|
static_cast<VkDeviceSize>(indexDataSizeBytes), alignment, slice)) {
|
||||||
MGLOG_E("DrawElements skipped: failed to prepare index upload buffer");
|
MGLOG_E("DrawElements skipped: failed to prepare index upload buffer");
|
||||||
return false;
|
return false;
|
||||||
@@ -1283,8 +1272,7 @@ void main() {
|
|||||||
result = VK_SUCCESS;
|
result = VK_SUCCESS;
|
||||||
}
|
}
|
||||||
VK_VERIFY(result, "Present, vkAcquireNextImageKHR");
|
VK_VERIFY(result, "Present, vkAcquireNextImageKHR");
|
||||||
m_vertexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||||
m_indexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::CreateInstance() {
|
void VulkanRenderer::CreateInstance() {
|
||||||
@@ -1820,31 +1808,10 @@ void main() {
|
|||||||
m_frameContext.GetCurrent().isCommandRecording = false;
|
m_frameContext.GetCurrent().isCommandRecording = false;
|
||||||
m_frameContext.GetCurrent().hasCommandBufferRecorded = false;
|
m_frameContext.GetCurrent().hasCommandBufferRecorded = false;
|
||||||
}
|
}
|
||||||
m_vertexUploadArena.Shutdown();
|
const Bool okArena = m_bufferManager.RecreateTransientArenas(m_frameContext.GetFrameCount());
|
||||||
Bool okArena = m_vertexUploadArena.Initialize({
|
MOBILEGL_ASSERT(okArena, "RecreateSwapchain: buffer manager transient arena initialization failed");
|
||||||
.allocator = m_allocator,
|
|
||||||
.frameCount = m_frameContext.GetFrameCount(),
|
|
||||||
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
||||||
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
|
|
||||||
.allocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
|
||||||
.minBufferSize = 4 * 1024 * 1024,
|
|
||||||
.persistentlyMapped = false,
|
|
||||||
});
|
|
||||||
MOBILEGL_ASSERT(okArena, "RecreateSwapchain: vertex upload arena initialization failed");
|
|
||||||
m_indexUploadArena.Shutdown();
|
|
||||||
okArena = m_indexUploadArena.Initialize({
|
|
||||||
.allocator = m_allocator,
|
|
||||||
.frameCount = m_frameContext.GetFrameCount(),
|
|
||||||
.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
||||||
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
|
|
||||||
.allocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
|
||||||
.minBufferSize = 1 * 1024 * 1024,
|
|
||||||
.persistentlyMapped = false,
|
|
||||||
});
|
|
||||||
MOBILEGL_ASSERT(okArena, "RecreateSwapchain: index upload arena initialization failed");
|
|
||||||
if (m_frameContext.GetFrameCount() > 0) {
|
if (m_frameContext.GetFrameCount() > 0) {
|
||||||
m_vertexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||||
m_indexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "BufferArena.h"
|
|
||||||
#include "FrameContext.h"
|
#include "FrameContext.h"
|
||||||
#include "PipelineFactory.h"
|
#include "PipelineFactory.h"
|
||||||
#include "ProgramFactory.h"
|
#include "ProgramFactory.h"
|
||||||
@@ -16,6 +15,7 @@
|
|||||||
#include "UniformDescriptorBinder.h"
|
#include "UniformDescriptorBinder.h"
|
||||||
#include "VertexInputStateFactory.h"
|
#include "VertexInputStateFactory.h"
|
||||||
#include "VkBufferObject.h"
|
#include "VkBufferObject.h"
|
||||||
|
#include "VkBufferManager.h"
|
||||||
#include "VkClearManager.h"
|
#include "VkClearManager.h"
|
||||||
#include "VkRenderPassManager.h"
|
#include "VkRenderPassManager.h"
|
||||||
#include "VkSamplerManager.h"
|
#include "VkSamplerManager.h"
|
||||||
@@ -171,8 +171,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||||
|
|
||||||
BufferArena m_vertexUploadArena;
|
VkBufferManager m_bufferManager;
|
||||||
BufferArena m_indexUploadArena;
|
|
||||||
|
|
||||||
Uint m_imageIndexAcquired = 0;
|
Uint m_imageIndexAcquired = 0;
|
||||||
FrameContext m_frameContext;
|
FrameContext m_frameContext;
|
||||||
|
|||||||
Reference in New Issue
Block a user