KhronosGroup / MoltenVK

MoltenVK is a Vulkan Portability implementation. It layers a subset of the high-performance, industry-standard Vulkan graphics and compute API over Apple's Metal graphics framework, enabling Vulkan applications to run on macOS, iOS and tvOS.
Apache License 2.0
4.64k stars 402 forks source link

Low maxVariableDescriptorCount being reported #2203

Open MennoVink opened 3 months ago

MennoVink commented 3 months ago

I'm receiving a rather low variable descriptor count which i expected to be higher.

I'm on Intel Iris 6100 and these are my limits:

maxPerStageDescriptorSamplers   uint32_t    16
maxPerStageDescriptorUniformBuffers uint32_t    31
maxPerStageDescriptorStorageBuffers uint32_t    31
maxPerStageDescriptorSampledImages  uint32_t    128
maxPerStageDescriptorStorageImages  uint32_t    8
maxPerStageDescriptorInputAttachments   uint32_t    128
maxPerStageResources    uint32_t    159
maxDescriptorSetSamplers    uint32_t    80
maxDescriptorSetUniformBuffers  uint32_t    155
maxDescriptorSetUniformBuffersDynamic   uint32_t    155
maxDescriptorSetStorageBuffers  uint32_t    155
maxDescriptorSetStorageBuffersDynamic   uint32_t    155
maxDescriptorSetSampledImages   uint32_t    640
maxDescriptorSetStorageImages   uint32_t    40
maxDescriptorSetInputAttachments    uint32_t    640

The values important to me are 16 samplers and 128 sampled images (both per-stage). This is the layout for my descriptor set (glsl):

struct Constants
{
    mat4 world;
    int albedoIndex;
};
layout( std430, set = 0, binding = 0 ) readonly buffer buf
{
    Constants constants[];
};
layout( set = 0, binding = 1) uniform sampler albedoSampler;
layout( set = 0, binding = 2 ) uniform texture2D albedoImages[];

My layout bindings match this and i have bindFlags of 0, 0, 8 (variable only for the albedoImages).

Now when i call getDescriptorSetLayoutSupport attaching a DescriptorSetVariableDescriptorCountLayoutSupportEXT, i get the maximum variable count being 15.

Where does this 15 come from? How come it doesn't tell me that i can use 128 sampled images?

*edit: To add insult to injury, if i ask whether or not a layout using those 15 descriptors is supported it still tells me no. 14 is the highest amount that's reported as being supported. This seems to me like the same off-by-one issue i reported here https://github.com/KhronosGroup/MoltenVK/issues/1696.

MennoVink commented 3 months ago

I tried to get this to run in the cube example but it's configured to disallow debugging so not sure how to recreate it there.

Here's what i've got so far:

        VkDescriptorSetLayoutBinding bindings[ 3 ] = {};
        bindings[ 0 ].binding = 0;
        bindings[ 0 ].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
        bindings[ 0 ].descriptorCount = 1;
        bindings[ 0 ].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;

        bindings[ 1 ].binding = 1;
        bindings[ 1 ].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
        bindings[ 1 ].descriptorCount = 1;
        bindings[ 1 ].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;

        bindings[ 2 ].binding = 2;
        bindings[ 2 ].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
        bindings[ 2 ].descriptorCount = 0;
        bindings[ 2 ].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;

        VkDescriptorSetLayoutCreateInfo setLayoutCreateInfo = {};
        setLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
        setLayoutCreateInfo.bindingCount = 3;
        setLayoutCreateInfo.pBindings = bindings;

        VkDescriptorBindingFlags bindingFlags[ 3 ] = {};
        bindingFlags[ 2 ] = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT;

        VkDescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsCreateInfo = {};
        bindingFlagsCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
        bindingFlagsCreateInfo.bindingCount = 3;
        bindingFlagsCreateInfo.pBindingFlags = bindingFlags;
        setLayoutCreateInfo.pNext = &bindingFlagsCreateInfo;

        VkDescriptorSetVariableDescriptorCountLayoutSupport variableCountSupport = {};
        variableCountSupport.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT;
        VkDescriptorSetLayoutSupport descriptorSupport = {};
        descriptorSupport.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT;
        descriptorSupport.pNext = &variableCountSupport;

        vkGetDescriptorSetLayoutSupport( demo->device, &setLayoutCreateInfo, &descriptorSupport );
        assert( variableCountSupport.maxVariableDescriptorCount == 128 );

Obviously it also needs the indexing features:

    VkPhysicalDeviceDescriptorIndexingFeatures indexingFeatures = {};
    indexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES;
    indexingFeatures.runtimeDescriptorArray = true;
    indexingFeatures.descriptorBindingVariableDescriptorCount = true;
    VkPhysicalDeviceFeatures2 enabledFeatures2 = {};
    enabledFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    enabledFeatures2.pNext = &indexingFeatures;

And the extension:

        for (uint32_t i = 0; i < device_extension_count; i++) {
            if (!strcmp(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, device_extensions[i].extensionName)) {
                demo->extension_names[demo->enabled_extension_count++] = VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME;
            }
        }