uniform缓冲

在下一章节,我们将会为着色器指定包含UBO数据的缓冲对象。我们首先需要创建用于包含数据的缓冲对象,然后在每一帧将新的UBO数据复制到uniform缓冲。由于需要频繁的数据更新,在这里使用暂存缓冲并不会带来性能提升。

由于我们同时并行渲染多帧的缘故,我们需要多个uniform缓冲,来满足多帧并行渲染的需要。我们可以对并行渲染的每一帧或每一个交换链图像使用独立的uniform缓冲对象。由于我需要在指令缓冲中引用uniform缓冲,对于每个交换链图像使用独立的uniform缓冲对象相对来说更加方便。

添加两个新的类成员变量uniformBuffers和uniformBuffersMemory:

VkBuffer indexBuffer;
VkDeviceMemory indexBufferMemory;

std::vector<VkBuffer> uniformBuffers;
std::vector<VkDeviceMemory> uniformBuffersMemory;

添加一个叫做createUniformBuffers的函数,在createIndexBuffer函数调用后调用它分配uniform缓冲对象:

void initVulkan() {
        ...
    createVertexBuffer();
    createIndexBuffer();
    createUniformBuffer();
        ...
}

        ...

void createUniformBuffer() {
    VkDeviceSize bufferSize = sizeof(UniformBufferObject);

    uniformBuffers.resize(swapChainImages.size());
    uniformBuffersMemory.resize(swapChainImages.size());

    for (size_t i = 0; i < swapChainImages.size(); i++) {
        createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
    }
}

我们会在另外的函数中使用新的变换矩阵更新uniform缓冲,所以在这里没有出现vkMapMemory函数调用。应用程序退出前不要忘记清除申请的uniform缓冲对象:

void cleanup() {
    cleanupSwapChain();

    vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);

    for (size_t i = 0; i < swapChainImages.size(); i++) {
        vkDestroyBuffer(device, uniformBuffers[i], nullptr);
        vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
    }

        ...
}