Vulkan-ValidationLayers icon indicating copy to clipboard operation
Vulkan-ValidationLayers copied to clipboard

Validate VUID-RuntimeSpirv-Location-06428

Open Rua opened this issue 1 year ago • 1 comments

This VUID is not validated anywhere in the layer's source code:

VUID-RuntimeSpirv-Location-06428 The maximum number of storage buffers, storage images, and output Location decorated color attachments written to in the Fragment Execution Model must be less than or equal to maxFragmentCombinedOutputResources

Rua avatar Jan 27 '24 16:01 Rua

yes, this is similar to the maxFragmentDualSrcAttachments one (VUID-vkCmdDraw-maxFragmentDualSrcAttachments-09239) that we have coverage for

I remember I was going to do this one, but needed spec clarification (which was added https://gitlab.khronos.org/vulkan/vulkan/-/issues/2236) and just never got around back to adding this

spencer-lunarg avatar Jan 28 '24 03:01 spencer-lunarg

wow, so finally got to this and tried to implement it as


    // maxFragmentCombinedOutputResources
    if (stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
        // Variables can be aliased, so use Location to mark things as unique
        vvl::unordered_set<uint32_t> color_attachments;
        vvl::unordered_set<uint32_t> storage_buffers;
        vvl::unordered_set<uint32_t> storage_images;
        for (const auto *variable : entrypoint.user_defined_interface_variables) {
            if (variable->storage_class == spv::StorageClassOutput && variable->decorations.location != spirv::kInvalidValue) {
                // even if using an array of attachments in the shader, each used variable of the array is represented by a single variable
                color_attachments.insert(variable->decorations.location);
            }
        }

        for (const auto& variable : entrypoint.resource_interface_variables) {
            if (variable.decorations.location == spirv::kInvalidValue) continue;
            if (variable.is_storage_buffer) {
                storage_buffers.insert(variable.decorations.location);
            } else if (variable.is_storage_image) {
                storage_images.insert(variable.decorations.location);
            }
        }
        const uint32_t total_output = (uint32_t)(color_attachments.size() + storage_buffers.size() + storage_images.size());
        if (total_output > limits.maxFragmentCombinedOutputResources) {
            skip |= LogError("VUID-RuntimeSpirv-Location-06428", module_state.handle(), loc,
                                "SPIR-V (Fragment stage) output contains %zu storage buffer locations, %zu storage image locations, and %zu color attachments which together is %" PRIu32 " which exceeds the limit maxFragmentCombinedOutputResources (%" PRIu32 ").", storage_buffers.size(), storage_images.size(), color_attachments.size(), total_output, limits.maxFragmentCombinedOutputResources);
        }
    }

but then writing tests, I realized I have no idea what the "storage buffer" means (like do we count each set or each binding to the limit?)

created https://gitlab.khronos.org/vulkan/vulkan/-/issues/3900 to try this spec fixing again :crying_cat_face:

update - found out this was before descriptor indexing (and those drivers should report something like uint32_t max here). Also each descriptor (so binding) would count as 1

spencer-lunarg avatar Jun 06 '24 02:06 spencer-lunarg