创建Uniform缓冲区
本节的代码是 07-init_uniform_buffer.cpp
Uniform缓冲区是一个访问只读着色器的缓冲区,以便着色器可以读取常量参数数据。
这是另一个你必须在Vulkan程序中执行的步骤。在GLES中,你只需要做一个API调用来设置发送给着色器的统一变量的内容。而在这里,你必须分配内存并将其填充。
设置 Uniform 数据
样例使用Uniform缓冲区将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.
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缓冲区对象
创建这个缓冲区与你在之前的示例中创建深度缓冲的方式非常相似,只是对用法进行了更改:
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 缓冲区内存
像深度缓冲一样,您需要显式地为Uniform缓冲区分配内存。
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(主机)能够访问它。
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
要求主机对内存的写入是可见的(反之亦然),而不需要刷新内存缓存。这只会让编程变得更简单,因为没有必要调用vkFlushMappedMemoryRanges
和vkInvalidateMappedMemoryRanges
,以确保数据对GPU是可见的。
映射和设置Uniform 缓冲区内存
当您在先前的示例中分配深度缓冲区时,您不需要初始化深度缓冲内存的内容。这是因为GPU会负责阅读和编写它。但是在uniform 缓冲区,您需要用您希望着色器读取的数据填充它。在这里,数据是MVP矩阵。为了获得对内存的CPU访问,您需要映射它:
res = vkMapMemory(info.device, info.uniform_data.mem, 0, mem_reqs.size, 0,
(void **)&pData);
这是一个非常简单的事情,把MVP复制到统一的缓冲区中,然后把它解出来:
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);
结束。
© Copyright 2016 LunarG, Inc