mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Feat] (MG_Backend/DirectVulkan): VkBufferManager transient upload now includes uniform
This commit is contained in:
@@ -174,14 +174,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::Initialize(VkDevice device, VmaAllocator allocator,
|
||||
Bool UniformDescriptorBinder::Initialize(VkDevice device, VkBufferManager* bufferManager,
|
||||
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
||||
Uint32 maxBindings, Uint32 setsPerFrame, VkDeviceSize perFrameUploadBytes,
|
||||
Uint32 maxBindings, Uint32 setsPerFrame,
|
||||
VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
|
||||
Shutdown();
|
||||
|
||||
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
|
||||
MOBILEGL_ASSERT(allocator != nullptr, "UniformDescriptorBinder::Initialize requires valid VMA allocator");
|
||||
MOBILEGL_ASSERT(bufferManager != nullptr, "UniformDescriptorBinder::Initialize requires valid buffer manager");
|
||||
MOBILEGL_ASSERT(frameCount > 0, "UniformDescriptorBinder::Initialize requires frameCount > 0");
|
||||
MOBILEGL_ASSERT(maxBindings > 0, "UniformDescriptorBinder::Initialize requires maxBindings > 0");
|
||||
MOBILEGL_ASSERT(setsPerFrame > 0, "UniformDescriptorBinder::Initialize requires setsPerFrame > 0");
|
||||
@@ -191,9 +191,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
"UniformDescriptorBinder::Initialize requires valid sampler manager");
|
||||
|
||||
m_device = device;
|
||||
m_allocator = allocator;
|
||||
m_bufferManager = bufferManager;
|
||||
m_minDynamicOffsetAlignment = std::max<VkDeviceSize>(1, minUniformBufferOffsetAlignment);
|
||||
m_perFrameUploadBytes = perFrameUploadBytes;
|
||||
m_frameCount = frameCount;
|
||||
m_maxBindings = maxBindings;
|
||||
m_setsPerFrame = setsPerFrame;
|
||||
@@ -204,7 +203,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_frames.resize(m_frameCount);
|
||||
for (Uint32 frameIndex = 0; frameIndex < m_frameCount; ++frameIndex) {
|
||||
auto& frame = m_frames[frameIndex];
|
||||
frame.writeCursor = 0;
|
||||
frame.activeDescriptorPoolIndex = 0;
|
||||
frame.allocatedSetsThisFrame = 0;
|
||||
frame.peakAllocatedSetsThisFrame = 0;
|
||||
@@ -219,15 +217,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
frame.descriptorPools.push_back({initialPool, m_setsPerFrame, 0});
|
||||
MGLOG_D("UniformDescriptorBinder: frame %u descriptor pool created (maxSets=%u)", frameIndex, m_setsPerFrame);
|
||||
|
||||
const Bool created = frame.uploadBuffer.Create(
|
||||
m_allocator, m_perFrameUploadBytes, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO,
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT);
|
||||
if (!created) {
|
||||
MGLOG_E("UniformDescriptorBinder::Initialize failed: cannot create frame upload buffer %u", frameIndex);
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -235,7 +224,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
void UniformDescriptorBinder::Shutdown() {
|
||||
for (auto& frame : m_frames) {
|
||||
frame.uploadBuffer.Destroy();
|
||||
if (m_device != VK_NULL_HANDLE) {
|
||||
for (auto& bucket : frame.descriptorPools) {
|
||||
if (bucket.handle != VK_NULL_HANDLE) {
|
||||
@@ -248,15 +236,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
frame.activeDescriptorPoolIndex = 0;
|
||||
frame.allocatedSetsThisFrame = 0;
|
||||
frame.peakAllocatedSetsThisFrame = 0;
|
||||
frame.writeCursor = 0;
|
||||
}
|
||||
m_frames.clear();
|
||||
DestroyProgramLayouts();
|
||||
|
||||
m_allocator = nullptr;
|
||||
m_bufferManager = nullptr;
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_minDynamicOffsetAlignment = 1;
|
||||
m_perFrameUploadBytes = 0;
|
||||
m_frameCount = 0;
|
||||
m_maxBindings = 0;
|
||||
m_setsPerFrame = 0;
|
||||
@@ -274,7 +260,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
"UniformDescriptorBinder: new descriptor set peak observed=%u (base setsPerFrame=%u, frame=%u, pools=%zu)",
|
||||
m_peakDescriptorSetsObserved, m_setsPerFrame, frameIndex, frame.descriptorPools.size());
|
||||
}
|
||||
frame.writeCursor = 0;
|
||||
frame.activeDescriptorPoolIndex = 0;
|
||||
frame.allocatedSetsThisFrame = 0;
|
||||
frame.peakAllocatedSetsThisFrame = 0;
|
||||
@@ -678,16 +663,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return layout ? layout->pipelineLayout : VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::AllocateUploadRegion(FrameResources& frame, VkDeviceSize size, VkDeviceSize& outOffset) {
|
||||
const VkDeviceSize alignedOffset = AlignUp(frame.writeCursor, m_minDynamicOffsetAlignment);
|
||||
if (alignedOffset + size > m_perFrameUploadBytes) {
|
||||
return false;
|
||||
}
|
||||
outOffset = alignedOffset;
|
||||
frame.writeCursor = alignedOffset + size;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::GatherBindingPayloads(const MG_State::GLState::ProgramObject& program,
|
||||
Vector<const void*>& outData,
|
||||
Vector<VkDeviceSize>& outSizes) const {
|
||||
@@ -870,6 +845,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static const Uint8 kFallbackData[16] = {};
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "BindProgramUniformBuffers: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "BindProgramUniformBuffers: sampler manager is null");
|
||||
MOBILEGL_ASSERT(m_bufferManager != nullptr, "BindProgramUniformBuffers: buffer manager is null");
|
||||
|
||||
Vector<VkWriteDescriptorSet> writes;
|
||||
writes.reserve(m_maxBindings);
|
||||
@@ -911,19 +887,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
|
||||
VkDeviceSize payloadOffset = 0;
|
||||
if (!AllocateUploadRegion(frame, payloadSize, payloadOffset)) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: frame upload buffer exhausted");
|
||||
return false;
|
||||
}
|
||||
if (!frame.uploadBuffer.Upload(payload, payloadSize, payloadOffset)) {
|
||||
BufferSlice slice{};
|
||||
if (!m_bufferManager->UploadTransient(TransientBufferKind::Uniform, frameIndex, payload, payloadSize,
|
||||
m_minDynamicOffsetAlignment, slice)) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: UBO upload failed on binding %u",
|
||||
binding);
|
||||
return false;
|
||||
}
|
||||
|
||||
VkDescriptorBufferInfo bufferInfo{};
|
||||
bufferInfo.buffer = frame.uploadBuffer.GetHandle();
|
||||
bufferInfo.buffer = slice.buffer;
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = payloadSize;
|
||||
bufferInfos.push_back(bufferInfo);
|
||||
@@ -931,7 +904,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||
write.pBufferInfo = &bufferInfos.back();
|
||||
writes.push_back(write);
|
||||
dynamicOffsets.push_back(static_cast<Uint32>(payloadOffset));
|
||||
dynamicOffsets.push_back(static_cast<Uint32>(slice.offset));
|
||||
} else {
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
Bool hasImage = false;
|
||||
|
||||
@@ -8,12 +8,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VkBufferObject.h"
|
||||
#include "VkBufferManager.h"
|
||||
#include "VkSamplerManager.h"
|
||||
#include "VkTextureManager.h"
|
||||
#include "../VkIncludes.h"
|
||||
#include <Includes.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class ITextureObject;
|
||||
@@ -36,9 +35,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const MG_State::GLState::SamplerObject* sampler = nullptr;
|
||||
};
|
||||
|
||||
Bool Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment,
|
||||
Uint32 frameCount, Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
||||
VkDeviceSize perFrameUploadBytes = 4 * 1024 * 1024,
|
||||
Bool Initialize(VkDevice device, VkBufferManager* bufferManager,
|
||||
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
||||
Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
||||
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
|
||||
void Shutdown();
|
||||
|
||||
@@ -60,12 +59,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
};
|
||||
|
||||
struct FrameResources {
|
||||
VkBufferObject uploadBuffer;
|
||||
Vector<DescriptorPoolBucket> descriptorPools;
|
||||
Uint32 activeDescriptorPoolIndex = 0;
|
||||
Uint32 allocatedSetsThisFrame = 0;
|
||||
Uint32 peakAllocatedSetsThisFrame = 0;
|
||||
VkDeviceSize writeCursor = 0;
|
||||
};
|
||||
|
||||
struct ProgramLayout {
|
||||
@@ -94,7 +91,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool ReflectBindingKinds(const MG_State::GLState::ProgramObject& program, Vector<BindingKind>& outKinds) const;
|
||||
ProgramLayout* GetOrCreateProgramLayout(const MG_State::GLState::ProgramObject& program);
|
||||
Bool AllocateUploadRegion(FrameResources& frame, VkDeviceSize size, VkDeviceSize& outOffset);
|
||||
Bool GatherBindingPayloads(const MG_State::GLState::ProgramObject& program, Vector<const void*>& outData,
|
||||
Vector<VkDeviceSize>& outSizes) const;
|
||||
Bool CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const;
|
||||
@@ -102,12 +98,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void DestroyProgramLayouts();
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VmaAllocator m_allocator = nullptr;
|
||||
VkBufferManager* m_bufferManager = nullptr;
|
||||
Vector<FrameResources> m_frames;
|
||||
UnorderedMap<Uint64, ProgramLayout> m_programLayouts;
|
||||
|
||||
VkDeviceSize m_minDynamicOffsetAlignment = 1;
|
||||
VkDeviceSize m_perFrameUploadBytes = 0;
|
||||
Uint32 m_frameCount = 0;
|
||||
Uint32 m_maxBindings = 0;
|
||||
Uint32 m_setsPerFrame = 0;
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void VkBufferManager::Shutdown() {
|
||||
m_vertexUploadArena.Shutdown();
|
||||
m_indexUploadArena.Shutdown();
|
||||
m_uniformUploadArena.Shutdown();
|
||||
m_initInfo = {};
|
||||
}
|
||||
|
||||
@@ -31,6 +32,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
m_vertexUploadArena.Shutdown();
|
||||
m_indexUploadArena.Shutdown();
|
||||
m_uniformUploadArena.Shutdown();
|
||||
m_initInfo.frameCount = frameCount;
|
||||
return InitializeTransientArenas();
|
||||
}
|
||||
@@ -38,6 +40,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void VkBufferManager::BeginFrame(Uint32 frameIndex) {
|
||||
m_vertexUploadArena.BeginFrame(frameIndex);
|
||||
m_indexUploadArena.BeginFrame(frameIndex);
|
||||
m_uniformUploadArena.BeginFrame(frameIndex);
|
||||
}
|
||||
|
||||
Bool VkBufferManager::UploadTransient(TransientBufferKind kind, Uint32 frameIndex, const void* data,
|
||||
@@ -47,6 +50,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return m_vertexUploadArena.Upload(frameIndex, data, size, alignment, outSlice);
|
||||
case TransientBufferKind::Index:
|
||||
return m_indexUploadArena.Upload(frameIndex, data, size, alignment, outSlice);
|
||||
case TransientBufferKind::Uniform:
|
||||
return m_uniformUploadArena.Upload(frameIndex, data, size, alignment, outSlice);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -80,6 +85,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = m_uniformUploadArena.Initialize({
|
||||
.allocator = m_initInfo.allocator,
|
||||
.frameCount = m_initInfo.frameCount,
|
||||
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
.memoryUsage = m_initInfo.transientMemoryUsage,
|
||||
.allocationFlags = m_initInfo.transientAllocationFlags,
|
||||
.minBufferSize = m_initInfo.minUniformUploadBytes,
|
||||
.persistentlyMapped = m_initInfo.transientPersistentMapping,
|
||||
});
|
||||
if (!ok) {
|
||||
m_vertexUploadArena.Shutdown();
|
||||
m_indexUploadArena.Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
enum class TransientBufferKind : Uint8 {
|
||||
Vertex,
|
||||
Index,
|
||||
Uniform,
|
||||
};
|
||||
|
||||
struct VkBufferManagerInitInfo {
|
||||
@@ -24,6 +25,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 frameCount = 0;
|
||||
VkDeviceSize minVertexUploadBytes = 4 * 1024 * 1024;
|
||||
VkDeviceSize minIndexUploadBytes = 1 * 1024 * 1024;
|
||||
VkDeviceSize minUniformUploadBytes = 4 * 1024 * 1024;
|
||||
VmaMemoryUsage transientMemoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||
VmaAllocationCreateFlags transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
Bool transientPersistentMapping = false;
|
||||
@@ -47,5 +49,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkBufferManagerInitInfo m_initInfo{};
|
||||
BufferArena m_vertexUploadArena;
|
||||
BufferArena m_indexUploadArena;
|
||||
BufferArena m_uniformUploadArena;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -293,6 +293,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
.frameCount = m_frameContext.GetFrameCount(),
|
||||
.minVertexUploadBytes = 4 * 1024 * 1024,
|
||||
.minIndexUploadBytes = 1 * 1024 * 1024,
|
||||
.minUniformUploadBytes = 4 * 1024 * 1024,
|
||||
.transientMemoryUsage = VMA_MEMORY_USAGE_AUTO,
|
||||
.transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||
.transientPersistentMapping = false,
|
||||
@@ -329,9 +330,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
m_uniformDescriptorBinder = MakeUnique<UniformDescriptorBinder>();
|
||||
MOBILEGL_ASSERT(m_uniformDescriptorBinder != nullptr, "UniformDescriptorBinder creation failed.");
|
||||
succeeded = m_uniformDescriptorBinder->Initialize(m_device, m_allocator,
|
||||
succeeded = m_uniformDescriptorBinder->Initialize(m_device, &m_bufferManager,
|
||||
m_physicalDevice.properties.limits.minUniformBufferOffsetAlignment,
|
||||
m_config.MaxFramesInFlight, 16, 64, 4 * 1024 * 1024,
|
||||
m_config.MaxFramesInFlight, 16, 64,
|
||||
m_textureManager.get(), m_samplerManager.get());
|
||||
MOBILEGL_ASSERT(succeeded, "UniformDescriptorBinder initialization failed.");
|
||||
m_vertexInputStateFactory = MakeUnique<VertexInputStateFactory>(m_config);
|
||||
|
||||
Reference in New Issue
Block a user