Vulkan Tutorial 7 创建Uniform Buffer

Uniform Buffer可以以只读方式访问着色器,以便着色器可以读取常量参数数据。

在Vulkan里面,程序员必须自己创建Uniform Buffer,在其他API里面则不需要。

设置Uniform数据

程序可使用Uniform缓冲将MVP(Model-View-Projection)矩阵传入着色器,着色器通过MVP数据对每一个顶点进行变换。

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.
// clang-format off
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);
// clang-format on
info.MVP = info.Clip * info.Projection * info.View * info.Model;

申请Uniform 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)可见,所以CPU才可以访问这个内存。

VK_MEMORY_PROPERTY_HOST_COHERENT_BIT表示主机对内存的写入对设备可见(反之亦然),而无需刷新内存缓存。使用VK_MEMORY_PROPERTY_HOST_COHERENT_BIT只是使代码更简单,因为没有必要调用vkFlushMappedMemoryRanges和vkInvalidateMappedMemoryRanges来确保数据对GPU可见。

映射和设置Uniform Buffer

对于深度缓冲,不需要初始化这块内存的内容,因为深度缓冲是由GPU负责读写的。Uniform Buffer则不然,必须填充想要让着色器读取的内容到该缓冲。在这里,这个数据是MVP矩阵。为了让CPU能够访问这块内存,必须映射到这块内存:

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

接下来就是拷贝数据,然后取消映射:

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

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

因为因为内存映射机制(如页表)的大小有限,尤其是对于CPU和GPU都可见的内存,因此必须立即取消映射。

最后,必须将申请到的内存和缓冲对象进行绑定:

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

 

你可能感兴趣的:(vulkan)