【问题标题】:How do I load multiple structs into a single UBO?如何将多个结构加载到单个 UBO 中?
【发布时间】:2019-03-29 22:57:35
【问题描述】:

我正在关注以下教程:Here

我已经完成了加载模型,所以我的代码与那一点相似。

我现在正尝试将另一个结构传递给统一缓冲区对象,方法与之前显示的类似。

我创建了另一个在应用程序外部定义的结构来存储数据,如下所示:

struct Light{
    alignas(16) glm::vec3 position;
    alignas(16) glm::vec3 colour;
};

完成此操作后,我通过以下方式调整统一缓冲区大小:

    void createUniformBuffers() {
        VkDeviceSize bufferSize = sizeof(CameraUBO) + sizeof(Light);
    ...

接下来,在创建描述符集的时候,我在已经定义好的bufferInfo下面添加了lightBufferInfo,如下图:

        ...
        for (size_t i = 0; i < swapChainImages.size(); i++) {
            VkDescriptorBufferInfo bufferInfo = {};
            bufferInfo.buffer = uniformBuffers[i];
            bufferInfo.offset = 0;
            bufferInfo.range = sizeof(UniformBufferObject);

            VkDescriptorBufferInfo lightBufferInfo = {};
            lightBufferInfo.buffer = uniformBuffers[i];
            lightBufferInfo.offset = 0;
            lightBufferInfo.range = sizeof(Light);

        ...

然后我将它添加到descriptorWrites 数组中:

        ...
        descriptorWrites[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
        descriptorWrites[2].dstSet = descriptorSets[i];
        descriptorWrites[2].dstBinding = 2;
        descriptorWrites[2].dstArrayElement = 0;
        descriptorWrites[2].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
        descriptorWrites[2].descriptorCount = 1;
        descriptorWrites[2].pBufferInfo = &lightBufferInfo;
        ...

现在与 UniformBufferObject 类似,我计划使用 updateUniformBuffer(uint32_t currentImage) 函数来更改灯光的位置和颜色,但首先我只是尝试将位置设置为所需的值:

    void updateUniformBuffer(uint32_t currentImage) {
        ...
        ubo.proj[1][1] *= -1;

        Light light = {};
        light.position = glm::vec3(0, 10, 10);
        light.colour = glm::vec3(1, 1, 0);

        void* data;
        vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
        memcpy(data, &ubo, sizeof(ubo));
        vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
    }

我不明白在尝试将两个对象传递到统一缓冲区时偏移是如何工作的,所以我不知道如何将灯光对象复制到uniformBuffersMemory

如何定义偏移量以使其正常工作?

【问题讨论】:

    标签: c++ buffer offset vulkan


    【解决方案1】:

    进一步阅读之前的注意事项:将单个 UBO 的数据拆分为两个不同的结构和描述符会使传递数据变得更加复杂,因为您的所有大小和写入都需要与设备的 minUniformBufferAlignment 属性对齐,这使得你的代码有点复杂。如果您从 Vulkan 开始,您可能希望将数据拆分为两个 UBO(创建两个缓冲区),或者将所有值作为单个结构传递。

    但如果你想继续你在帖子中描述的方式:

    首先,您需要正确调整数组的大小,因为您的副本需要与minUniformBufferAlignment 对齐,您可能不能只将光照数据复制到其他数据之后的区域。如果您的设备有一个 256 字节的 minUniformBufferAlignment,并且您想要复制两个主机结构,那么您的统一缓冲区大小需要至少为 2 * 256 字节,而不仅仅是 sizeof(matrices) + sizeof(lights)。所以你需要相应地调整VkDeviceSize结构中的bufferSize

    接下来你需要抵消你的lightBufferInfoVkDescriptorBufferInfo

    lightBufferInfo.offset = std::max(sizeof(Light), minUniformBufferOffsetAlignment);
    

    这将使您的顶点着色器知道从哪里开始获取该绑定的数据。

    在大多数 NVidia GPU 上,例如,minUniformBufferOffsetAlignment 是 256 字节,而 Light 结构的大小是 32 字节。因此,要在这样的 GPU 上进行这项工作,您必须对齐 256 字节而不是 32 字节。

    在 RenderDoc 中检查您的设置应如下所示:

    请注意,对于更复杂的分配和场景,您需要根据数据结构的大小正确获得正确的对齐大小,而不是像上面那样使用简单的max

    现在在更新统一缓冲区时,您也需要映射并复制到正确的偏移量:

    void* mapped = nullptr;
    
    // Copy matrix data to offset for binding 0
    vkMapMemory(device, uniformBuffersMemory[currentImage].memory, 0, sizeof(ubo), 0, &mapped);
    memcpy(mapped, &ubo, sizeof(ubo));
    vkUnmapMemory(device, uniformBuffersMemory[currentImage].memory);
    
    // Copy light data to offset for binding 1 
    vkMapMemory(device, uniformBuffersMemory[currentImage].memory, std::max(sizeof(ubo), minUniformBufferOffsetAlignment), sizeof(Light), 0, &mapped);
    
    memcpy(mapped, &uboLight, sizeof(Light));
    vkUnmapMemory(device, uniformBuffersMemory[currentImage].memory);
    

    请注意,出于性能原因,您可能只想在创建缓冲区后映射一次,而不是在每次更新时映射。只需将偏移量指针存储在代码中的某个位置即可。

    【讨论】:

    • 谢谢。如果我要创建两个缓冲区,是否可以在 createUniformBuffers() 函数中通过 createBuffer(bufferSize1, ...createBuffer(bufferSize2, ... 为每个交换链图像完成?
    • 是的,您必须为您的lightBufferInfo 创建另一个仅包含轻数据的缓冲区(每个交换链图像)并将其绑定到VkDescriptorBufferInfo
    • 感谢您的帮助。就性能而言,哪一种方法明显快于另一种?
    猜你喜欢
    • 2020-03-06
    • 2021-11-24
    • 2020-10-11
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 2021-03-08
    • 1970-01-01
    • 2015-01-05
    相关资源
    最近更新 更多