Vulkan教程翻译之八 创建 Uniform Buffer

原文链接:https://vulkan.lunarg.com/doc/sdk/1.2.131.2/windows/tutorial/html/07-init_uniform_buffer.html

创建 Uniform Buffer

这一章节的代码文件是 07-init_uniform_buffer.cpp

你在最近的示例中已经创建过缓冲区,不妨现在再处理另一个。

uniform buffer 是一个面向 shader 以只读方式访问的缓冲区,以使 shader 能够读取静态参数的数据。

这又是一个例子,这一步是你在 Vulkan 程序里必须处理的,在其他图形API里就不必做。在 GLES 里,你只要简单的调一下API来设置发送给 shader 的 uniform 变量的内容。但是在这,你必须分配内存并且填写。

生成 Uniform Data

示例使用 uniform buffer 来传递 MVP(Model-View-Projection) 矩阵给 shader ,好让 shader 可以使用矩阵来转换顶点。

示例里像这样来生成数据:

info.Projection = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 100.0f);
info.View = glm::lookAt(
    glm::vec3(-5, 3, -10), // Camera is at (-5,3,-10), in World Space
    glm::vec3(0, 0, 0),    // and looks at the origin
    glm::vec3(0, -1, 0)    // Head is up (set to 0,-1,0 to look upside-down)
    );
info.Model = glm::mat4(1.0f);
// Vulkan clip space has inverted Y and half Z.
info.Clip = glm::mat4(1.0f,  0.0f, 0.0f, 0.0f,
                      0.0f, -1.0f, 0.0f, 0.0f,
                      0.0f,  0.0f, 0.5f, 0.0f,
                      0.0f,  0.0f, 0.5f, 1.0f);

info.MVP = info.Clip * info.Projection * info.View * info.Model;

请注意,这里用 glm 库来简化代码。info.MVP 是一个 4x4 矩阵。

创建 Uniform Buffer 对象

创建这个 buffer 和在前一个示例里你如何创建 depth buffer 非常相似,只是改变一下用法:

VkBufferCreateInfo buf_info = {};
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buf_info.pNext = NULL;
buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
buf_info.size = sizeof(info.MVP);
buf_info.queueFamilyIndexCount = 0;
buf_info.pQueueFamilyIndices = NULL;
buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
buf_info.flags = 0;
res = vkCreateBuffer(info.device, &buf_info, NULL, &info.uniform_data.buf);
assert(res == VK_SUCCESS);

分配 Uniform Buffer 内存

像 depth buffer 一样,你需要为 uniform buffer 显式地分配内存:

VkMemoryRequirements mem_reqs;
vkGetBufferMemoryRequirements(info.device, info.uniform_data.buf,
                              &mem_reqs);

VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.pNext = NULL;
alloc_info.memoryTypeIndex = 0;

alloc_info.allocationSize = mem_reqs.size;
pass = memory_type_from_properties(info, mem_reqs.memoryTypeBits,
                                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
                                       VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
                                   &alloc_info.memoryTypeIndex);

res = vkAllocateMemory(info.device, &alloc_info, NULL,
                       &(info.uniform_data.mem));

VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT 表示该内存应该被映射,以使 CPU(host) 能够访问它。

VK_MEMORY_PROPERTY_HOST_COHERENT_BIT 要求主机(host)对内存的写入对设备(device)可见(反之亦然),而不需要刷新内存的缓存。这对程序来说能简单一点,因为不必再调用 vkFlushMappedMemoryRanges 和 vkInvalidateMappedMemoryRanges 来确保数据对 GPU 可见。

映射和设置 Uniform Buffer 内存

在上一个示例中,在你分配 depth buffer 内存时,你不需要初始化它的内容。这是因为 GPU 负责读写它。但是对于 uniform buffer,你需要填充你想让 shader 读取的数据。当前情况下,数据是 MVP 矩阵。为了让 CPU 能访问内存,你需要映射:

res = vkMapMemory(info.device, info.uniform_data.mem, 0, mem_reqs.size, 0,
                  (void **)&pData);

拷贝 MVP 到 uniform buffer 里然后再取消映射就是相当简单的操作了:

memcpy(pData, &info.MVP, sizeof(info.MVP));

vkUnmapMemory(info.device, info.uniform_data.mem);

现在你就可以取消映射,因为我们在画一个静态的画面,不需要再更新MVP矩阵。但是如果你计划扩展这个示例来改变视野,保持着映射更高效。

最后,把你刚刚分配的内存和 buffer 对象关联起来:

res = vkBindBufferMemory(info.device, info.uniform_data.buf,
                         info.uniform_data.mem, 0);

好了,完成了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值