Vulkan创建顶点缓冲区

创建缓冲区:
添加新的函数createVertexBuffer,并在initVulkan函数中的createCommandBuffers函数之前调用。
Void initVulkan(){
createInstance();
setupDebugCallback();
createSurface();
pickPhysicalDevice();
createSwapChain();
createImageViews();
createRnderPass();
createGraphicsPipeline();
createFramebuffers();
createCommandPoll();
createVertexBuffer();
createCommandBuffers();
createSemaphores();
}

void createVertexBuffer(){
}
创建缓冲区需要填充VkBufferCreateInfo结构体。
VkBufferCreateInfo bufferInfo ={};
bufferInfo.sType =VK_STRUCTURE_TYPE_BUFF_CREATE_INFO;
bufferInfo.size =sizeof(vertices[0])*vertices.size();
结构体的第一个字段size指定缓冲区字节大小,计算缓冲区每个顶点数据的字节大小可以直接用sizeof。
BufferInfo.usage =VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
第二个字段usage,表示缓冲区的数据将如何使用。可以使用位操作指定多个使用目的,我们这里将会使用一个顶点缓冲区:
bufferInfo.sharingMode =VK_SHARING_MODE_EXCLUSIVE;
就像交换链中的图像一样,缓冲区也可以由特定的队列簇占有或者多个同时共享。
此处使用vkCreateBuffer函数创建缓冲区,定义一个类成员vertexBuffer存储缓冲区句柄。
VkBuffer vertexBuffer;
…,
void createVertexBuffer(){
VkBufferCreateInfo bufferInfo ={};
bufferInfo.sType =VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size =sizeof(vertices[0])*vertices.size();
bufferInfo.usage =VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
bufferInfo.sharingMode =VK_SHARING_MODE_EXCLUSIVE;

if(vkCreateBuffer(device,&bufferInfo,nullptr,&vertexBuffer) !=VK_SUCESS){
throw std::runtime_error(“fail to create vertex buffer!”);
}
}
缓冲区在程序退出之前为渲染命令rendering command提供支持,并且不依赖交换链,我们在cleanup函数中清理。
Void cleanup(){
cleanupSwapChain();
vkDestroyBuffer(device,vertexBuffer,nullptr);

}

内存需要:
虽然缓冲区建设完成,但是实际上并没有分配任何可用内存,给缓冲区分配内存的第一步是vkGetbufferMemoryRequirements函数查询内存需求。
VkMemoryRequirments memRequirements;
vkGetBufferMemoryRequirements(device,vertexBuffer,&memRequirements);
VkMemoryRequirements结构体有三个字段:
size:需要的内存字节大小,可能与bufferInfo.size大小不一致
alignment:缓冲区的内存分配区域开始的字节偏移量,它取决于bufferInfo.usage和bufferInfo.flags。
memoryTypeBits:适用于缓冲区的存储类型的字段。
显卡可以分配不同类型的内存。每种类型的内存根据所允许的操作和特性均不相同。我们需要结合缓冲区与应用程序的需要找到正确的内存类型使用。在此处添加一个新的函数完成此逻辑findMemoryType:
uint32_t findMemoryType(uint32_t typeFilter,VkMemoryPropertyFlags properties){
}
首先通过vkGetPhysicalDeviceMemoryProperties函数遍历有效的内存类型:
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice,&memProperties);
VkPhysicalDeviceMemoryProperties结构体有两个数组,一个是memoryTypes,另一个是memoryHeaps。内存堆是比较特别的内存资源,类似于VRAM内存以及在VRAM消耗尽时进行swap space中的RAM。在堆中存在不同类型的内存。
为缓冲区找到合适的内存类型:
for(uint32_t i=0;i<memProperties.memoryCount;i++){
if(typeFilter &(1<<i)){
return I;
}
}
throw std::runtime_error(“failed to find suitable memory type!”);
typeFilter参数将以位的形式代表合适的内存类型。这意味着通过简单的迭代内存属性集合,并根据需要的类型与每个内存属性的类型进行AND操作,判断是否为1。

内存分配:
在这里我们通过VkMemoryAllocateInfo结构体分配内存。
VkMemoryAllocateInfo allocInfo ={};
allocInfo.sType =VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.memoryTypeIndex =findMemoryType(memRequirements.memoryTypeBits,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
内存分配简单的指定大小和类型参数,这两个参数是从之前为顶点缓冲区设置的内存需求结构体和所需属性带过来的,创建一个类成员,存储使用vkAllocateMemory函数分配的内存句柄。
VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory;

if(vkAllocateMemory(device,&allocInfo,nullptr,&vertexBufferMemory)!=VK_SUCESS) {
throw std::runtime_error(“failed to allocate vertex buffer memory!”);
}
如果内存分配成功,我们使用vkBindBufferMemory函数将内存关联到缓冲区:
vkBindBufferMemory(device,vertexBuffer,vertexBufferMemory,0);
最后进行销毁:
void cleanup(){
cleanupSwapChain();

vkDestroyBuffer(device,vertexBuffer,nullptr);
vkFreeMemory(device,vertexBufferMemory,nullptr);
}

发布了146 篇原创文章 · 获赞 28 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_38498942/article/details/103911487
今日推荐