mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +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/UniformDescriptorBinder.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/VertexInputStateFactory.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@
|
||||
#define MOBILEGL_EGL_API MOBILEGL_API
|
||||
|
||||
// ====================== 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_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.");
|
||||
|
||||
CreateFrameContexts();
|
||||
succeeded = m_vertexUploadArena.Initialize({
|
||||
succeeded = m_bufferManager.Initialize({
|
||||
.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,
|
||||
.minVertexUploadBytes = 4 * 1024 * 1024,
|
||||
.minIndexUploadBytes = 1 * 1024 * 1024,
|
||||
.transientMemoryUsage = VMA_MEMORY_USAGE_AUTO,
|
||||
.transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||
.transientPersistentMapping = false,
|
||||
});
|
||||
MOBILEGL_ASSERT(succeeded, "Vertex upload arena 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.");
|
||||
MOBILEGL_ASSERT(succeeded, "Buffer manager initialization failed.");
|
||||
|
||||
// Prime the first frame so Render() always targets an acquired swapchain image.
|
||||
VK_VERIFY(m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired),
|
||||
"Initialize, WaitAndAcquireNextImage");
|
||||
m_vertexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_indexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
|
||||
MGLOG_D("VulkanRenderer initialized");
|
||||
}
|
||||
@@ -379,8 +368,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_textureManager.reset();
|
||||
}
|
||||
m_vertexInputStateFactory.reset();
|
||||
m_vertexUploadArena.Shutdown();
|
||||
m_indexUploadArena.Shutdown();
|
||||
m_bufferManager.Shutdown();
|
||||
|
||||
m_frameContext.Destroy(m_device, m_commandPool);
|
||||
|
||||
@@ -459,8 +447,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
const SizeT sourceSize = sourceBuffer->GetSize();
|
||||
BufferSlice slice{};
|
||||
if (!m_vertexUploadArena.Upload(frameIndex, sourceData->data(), static_cast<VkDeviceSize>(sourceSize), 16,
|
||||
slice)) {
|
||||
if (!m_bufferManager.UploadTransient(TransientBufferKind::Vertex, frameIndex, sourceData->data(),
|
||||
static_cast<VkDeviceSize>(sourceSize), 16, slice)) {
|
||||
MGLOG_E("UploadAndBindVertexStreams skipped: failed to upload binding %zu", binding);
|
||||
return false;
|
||||
}
|
||||
@@ -501,8 +489,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const Uint32 frameIndex = m_frameContext.GetCurrentFrameIndex();
|
||||
const VkDeviceSize alignment = indexSize;
|
||||
BufferSlice slice{};
|
||||
if (!m_indexUploadArena.Upload(frameIndex, indexData->data() + pIndexBufferView->indexByteOffset,
|
||||
static_cast<VkDeviceSize>(indexDataSizeBytes), alignment, slice)) {
|
||||
if (!m_bufferManager.UploadTransient(TransientBufferKind::Index, frameIndex,
|
||||
indexData->data() + pIndexBufferView->indexByteOffset,
|
||||
static_cast<VkDeviceSize>(indexDataSizeBytes), alignment, slice)) {
|
||||
MGLOG_E("DrawElements skipped: failed to prepare index upload buffer");
|
||||
return false;
|
||||
}
|
||||
@@ -1283,8 +1272,7 @@ void main() {
|
||||
result = VK_SUCCESS;
|
||||
}
|
||||
VK_VERIFY(result, "Present, vkAcquireNextImageKHR");
|
||||
m_vertexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_indexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
}
|
||||
|
||||
void VulkanRenderer::CreateInstance() {
|
||||
@@ -1820,31 +1808,10 @@ void main() {
|
||||
m_frameContext.GetCurrent().isCommandRecording = false;
|
||||
m_frameContext.GetCurrent().hasCommandBufferRecorded = false;
|
||||
}
|
||||
m_vertexUploadArena.Shutdown();
|
||||
Bool okArena = m_vertexUploadArena.Initialize({
|
||||
.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");
|
||||
const Bool okArena = m_bufferManager.RecreateTransientArenas(m_frameContext.GetFrameCount());
|
||||
MOBILEGL_ASSERT(okArena, "RecreateSwapchain: buffer manager transient arena initialization failed");
|
||||
if (m_frameContext.GetFrameCount() > 0) {
|
||||
m_vertexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_indexUploadArena.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#pragma once
|
||||
#include "Config.h"
|
||||
#include "BufferArena.h"
|
||||
#include "FrameContext.h"
|
||||
#include "PipelineFactory.h"
|
||||
#include "ProgramFactory.h"
|
||||
@@ -16,6 +15,7 @@
|
||||
#include "UniformDescriptorBinder.h"
|
||||
#include "VertexInputStateFactory.h"
|
||||
#include "VkBufferObject.h"
|
||||
#include "VkBufferManager.h"
|
||||
#include "VkClearManager.h"
|
||||
#include "VkRenderPassManager.h"
|
||||
#include "VkSamplerManager.h"
|
||||
@@ -171,8 +171,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||
|
||||
BufferArena m_vertexUploadArena;
|
||||
BufferArena m_indexUploadArena;
|
||||
VkBufferManager m_bufferManager;
|
||||
|
||||
Uint m_imageIndexAcquired = 0;
|
||||
FrameContext m_frameContext;
|
||||
|
||||
Reference in New Issue
Block a user