使用 Vulkan 映射内存时如何使用 std::vector<char> 而不是 void**?

How to use std::vector<char> instead of void** when mapping memory with Vulkan?

我一直在尝试从自定义游戏引擎中删除尽可能多的原始和 unique_ptr。 API 使用的是 Vulkan。目前,我对所有 vulkan 数据最简单的解决方案之一是使用简单的 std::vector<char>

但有一点我无法理解,那就是当我将内存映射到 LogicalDevice 时。

为了映射我的记忆,我使用了这个函数:

void Buffer::MapMemory(char** data) const {
    CheckVk(vkMapMemory(kLogicalDevice_, GetBufferMemory(), 0, size_, 0, reinterpret_cast<void**>(data)));
}

现在我从我的图形引擎的几个点调用这个函数,其中一个来自我的 UniformBuffer:

void UniformBuffer::Update(const std::vector<char>& newData) const {
    char* data;
    MapMemory(&data);
    std::memcpy(data, newData.data(), static_cast<std::size_t>(size_));
    UnmapMemory();
}

一个简单的函数,当我将数据映射到 GPU 时,在上面写入,然后取消映射。

我想删除 char* 并将其替换为 std::vector<char>


到目前为止我测试过的内容:

void UniformBuffer::Update(const std::vector<char>& newData) const {
    std::vector<char> data;
    MapMemory(reinterpret_cast<char**>(data.data()));
    std::memcpy(data.data(), newData.data(), static_cast<std::size_t>(size_));
    UnmapMemory();
}

程序编译通过,但数据似乎没有被映射,因为没有在 GPU 上写入任何内容。 (我什至查看了 RenderDoc,但似乎没有任何内容发送到 GPU)。

I wish to remove the char* and replace it with a std::vector<char>.

太好了。但这不会发生。

首先,停止将内存映射视为临时操作。如果您要映射一块内存,请在分配它时执行一次并保持指针。 vkUnmapMemory 只应在您要释放已映射的内存时调用。

还要映射 整个 内存块,因为任何单个内存分配只能映射一次。毫无疑问,您已经知道不要为要创建的 每个 单独缓冲区调用 vkAllocateMemory

其次,映射内存意味着 Vulkan 设备使 CPU 可用于 reading/writing 的内存(基于映射操作)。你不拥有那段记忆; Vulkan 设备拥有它。它只是与您共享该指针。

vector 拥有 它分配的内存。它通过用户指定的分配器类型对其进行分配和删除。

现在,您可能认为您可以创建一个 vector<char, MappedAllocator<char>>,其中 MappedAllocator 是一些分配器对象,"allocates" 它的内存来自映射指针。但这是行不通的。看,分配器分配内存,但 vector 决定 分配多少 内存以及何时分配。

如果无法控制 vector 可以尝试分配多少内存,那么在静态内存缓冲区上编写分配器并不是真正有效的方法。

如果您只想跟踪映射存储的大小,最好使用 gsl::span<char> 之类的东西。但除此之外,只要有一个指针并做指针式的事情。仅仅为此尝试编写自己的 vector 版本真的不值得。