Vulkan:一个管道和多个描述符集?

Posted

技术标签:

【中文标题】Vulkan:一个管道和多个描述符集?【英文标题】:Vulkan: one pipeline and multiple descriptor sets? 【发布时间】:2019-10-18 13:05:34 【问题描述】:

我正在尝试创建一个具有布局的单个管道,它需要两个绑定,一个动态 UBO 和一个图像/采样器绑定。我希望每个绑定都来自一个单独的描述符集,所以我会为每个绘制调用绑定两个描述符集。一个描述符集用于每个对象的纹理,另一个用于动态 UBO(在对象之间共享)。我希望能够在渲染部分做这样的事情:


commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);

for (int ii = 0; ii < mActiveQuads; ii++)

    uint32_t dynamicOffset = ii * static_cast<uint32_t>(dynamicAlignment);

    // bind texture for this quad
    commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, sharedPipelineLayout, 0, 1,
            &swapResources[current_buffer].textureDescriptors[ii], 1, &dynamicOffset);

    // draw the dynamic UBO with offset for this quad
    commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, sharedPipelineLayout, 0, 1,
                &swapResources[current_buffer].quadDescriptor, 1, &dynamicOffset);

    commandBuffer.draw(2 * 3, 1, 0, 0);

但这似乎不起作用。首先,我不确定我是否了解有关描述符集和管道布局的所有内容,以了解我正在做的事情是否被允许。这甚至有意义吗?我可以创建一个具有 2 个绑定布局的管道,但创建每个描述符以填充每个绑定中的一个,然后为该管道的每个绘制调用绑定两个描述符?

如果允许的话。这就是我创建管道和描述符的方式:

vk::DescriptorSetLayoutBinding const layout_bindings[2] =  vk::DescriptorSetLayoutBinding()
        .setBinding(0)
        .setDescriptorType(vk::DescriptorType::eUniformBufferDynamic)
        .setDescriptorCount(1)
        .setStageFlags(vk::ShaderStageFlagBits::eVertex)
        .setPImmutableSamplers(nullptr),
        vk::DescriptorSetLayoutBinding()
        .setBinding(1)
        .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
        .setDescriptorCount(1)//texture_count)
        .setStageFlags(vk::ShaderStageFlagBits::eFragment)
        .setPImmutableSamplers(nullptr) ;


    // note binding count is 1 here
    auto const descriptor_layout = vk::DescriptorSetLayoutCreateInfo().setBindingCount(1).setPBindings(&layout_bindings[0]); // using the first part of the above layout
    device.createDescriptorSetLayout(&descriptor_layout, nullptr, &quadDescriptorLayout);

    // note binding count is 1 here
    auto const descriptor_layout2 = vk::DescriptorSetLayoutCreateInfo().setBindingCount(1).setPBindings(&layout_bindings[1]); // using the second part of the above layout
    device.createDescriptorSetLayout(&descriptor_layout2, nullptr, &textureDescriptorLayout);

    // Now create the pipeline, note we use both the bindings above with
    // layout count = 2
    auto const pPipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo().setSetLayoutCount(2).setPSetLayouts(desc_layout);
    device.createPipelineLayout(&pPipelineLayoutCreateInfo, nullptr, &sharedPipelineLayout);

以及描述符本身:

    // alloc quad descriptor
    alloc_info =
        vk::DescriptorSetAllocateInfo()
            .setDescriptorPool(desc_pool)
            .setDescriptorSetCount(1)
            .setPSetLayouts(&quadDescriptorLayout);


     // texture descriptors(multiple descriptors, one per quad object)
    alloc_info =
        vk::DescriptorSetAllocateInfo()
            .setDescriptorPool(desc_pool)
            .setDescriptorSetCount(1)
            .setPSetLayouts(&textureDescriptorLayout);

以前,纹理和 UBO 在单个描述符集中工作正常,我可以看到多个四边形,但都共享一个纹理。当我将纹理拆分为不同的描述符集时,就会得到一个挂起的应用程序。尝试提交图形队列时出现“设备丢失”错误。

任何关于这是否可行或我在设置中做错了什么的见解将不胜感激。非常感谢!

下面添加Shader代码:

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(binding = 0) uniform UniformBufferObject 
    mat4 mvp;
    vec4 position[6];
    vec4 attr[6];
 ubo;


layout(location = 0) out vec2 fragTexCoord;

void main() 
    gl_Position = ubo.mvp *ubo.position[gl_VertexIndex];
    fragTexCoord = vec2(ubo.attr[gl_VertexIndex].x, ubo.attr[gl_VertexIndex].y);

像素着色器:

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(set=0, binding = 1) uniform sampler2D texSampler;

layout(location = 0) in vec2 fragTexCoord;

layout(location = 0) out vec4 outColor;

void main() 
    outColor = texture(texSampler, fragTexCoord);

【问题讨论】:

你的验证层说什么?你的着色器说什么? 嗨,Nicol,谢谢,我添加了着色器,但我认为 Jesse 遇到了以下问题。验证层什么也没说。 @Marvg 问题:为什么还要将 &dynamicOffset 传递给纹理的 bindDescriptorSets ? 【参考方案1】:

是的,您可以这样做。您的管道布局有两个描述符集。两个描述符集布局中的每一个都有一个描述符:一个动态 UBO 和一个纹理。在绘制时,您将每个描述符集布局的一个描述符集绑定到适当的集编号。

在绑定纹理描述符集时,firstSet 参数似乎是错误的:这是管道布局中的第二个集合,因此它的索引为 1,但您传递的是 0。验证层应该警告您,您正在将描述符集与集合布局绑定,该布局与管道布局对该集合的预期不匹配。

您没有显示访问这些的着色器代码,因此您可能已经这样做了。但是当从单个描述符集变为两个描述符集时,您需要更新采样器绑定中的集合索引。

【讨论】:

哇,谢谢杰西。它现在渲染,我还没有加载多个纹理,但我认为就是这样!它使用两个描述符呈现。不知道为什么验证层没有捕捉到任何东西。我也必须更改着色器访问。直到您刚才解释它,我才理解 firstSet 参数。谢谢。

以上是关于Vulkan:一个管道和多个描述符集?的主要内容,如果未能解决你的问题,请参考以下文章

Vulkan Tutorial 27 combined image sampler

Vulkan多线程渲染

我如何说服glslang向我提供有关未规划多维数组的反射信息?

管道符和作业控制shell变量环境变量配置文件

shell基础之管道符和变量

C多个进程写入1个管道