Vulkan Storage Buffer Memory Mapping

288 Views Asked by At

I'm refactoring and re-writing the guide made by VkGuide as to fit my idea of an engine. I'm using VMA to handle my memory needs.

I've stumbled upon a strange (?) issue in refactoring my memory mapping code into something more easily readable:

Original code:

Renderer fields

//-------------------------------------------------

struct ObjectData { matrix4 transform };

inline Frame& frame(); // Get current frame in flight

std::vector<RenderableObject> renderables;

//--------------------------------------------------

Drawing code

void* object_data;
vmaMapMemory(allocator, frame().object_buffer.allocation, &object_data);
auto* ssbo = static_cast<ObjectData*>(object_data);
for (int i = 0; i < renderables.size(); i++) {
    auto& object = renderables[i];
    ssbo[i].model_matrix = object.transform;
}
vmaUnmapMemory(allocator, frame().object_buffer.allocation)

and the refactored and templated namespace-local function:

struct AllocatedBuffer { VkBuffer buffer, VmaAllocation allocation }; 

template <typename T, typename Func>
void effect_mmap(VmaAllocator& allocator, AllocatedBuffer& buffer, Func&& effect)
{
    void* object_data;
    vmaMapMemory(allocator, buffer.allocation, &object_data);
    auto* t_pointer = static_cast<T*>(object_data);
    effect(*t_pointer);
    vmaUnmapMemory(allocator, buffer.allocation);
}

My camera position and everything else seems to shift and work incorrectly. Following shows usage (which now should replace the original code):

MemoryMapper::effect_mmap<ObjectData>(allocator, frame().object_buffer, [&](ObjectData& data) {
    for (auto& object : renderables) {
        data.model_matrix = object.transform;
    }
});

and here are the correct (the textures are still invalid, and I don't know why, that's for another day) and afters: Correct, and Incorrect.

1

There are 1 best solutions below

3
On BEST ANSWER

Your usage example only ever sets the first SSBO in the buffer, as data is *t_pointer and never changes. Change your code to pass t_pointer directly, change the type of the callback and then you can use it as

MemoryMapper::effect_mmap<ObjectData>(allocator, frame().object_buffer, [&](ObjectData* data) {
    for (auto& object : renderables) {
        data->model_matrix = object.transform;
        data++;
    }
});