使用 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)));
}
- CheckVk 是一个处理我所有 VkResults 的静态函数
- 在这个例子中,我试图隐藏
void**
并使用 char**
代替
现在我从我的图形引擎的几个点调用这个函数,其中一个来自我的 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
版本真的不值得。
我一直在尝试从自定义游戏引擎中删除尽可能多的原始和 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)));
}
- CheckVk 是一个处理我所有 VkResults 的静态函数
- 在这个例子中,我试图隐藏
void**
并使用char**
代替
现在我从我的图形引擎的几个点调用这个函数,其中一个来自我的 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 astd::vector<char>
.
太好了。但这不会发生。
首先,停止将内存映射视为临时操作。如果您要映射一块内存,请在分配它时执行一次并保持指针。 vkUnmapMemory
只应在您要释放已映射的内存时调用。
还要映射 整个 内存块,因为任何单个内存分配只能映射一次。毫无疑问,您已经知道不要为要创建的 每个 单独缓冲区调用 vkAllocateMemory
。
其次,映射内存意味着 Vulkan 设备使 CPU 可用于 reading/writing 的内存(基于映射操作)。你不拥有那段记忆; Vulkan 设备拥有它。它只是与您共享该指针。
vector
拥有 它分配的内存。它通过用户指定的分配器类型对其进行分配和删除。
现在,您可能认为您可以创建一个 vector<char, MappedAllocator<char>>
,其中 MappedAllocator
是一些分配器对象,"allocates" 它的内存来自映射指针。但这是行不通的。看,分配器分配内存,但 vector
决定 分配多少 内存以及何时分配。
如果无法控制 vector
可以尝试分配多少内存,那么在静态内存缓冲区上编写分配器并不是真正有效的方法。
如果您只想跟踪映射存储的大小,最好使用 gsl::span<char>
之类的东西。但除此之外,只要有一个指针并做指针式的事情。仅仅为此尝试编写自己的 vector
版本真的不值得。