blob: 26e63f75a75d62e3aeb593255ab5eb83dca57beb [file] [log] [blame]
/*
* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (c) 2015-2025 Google, Inc.
* Modifications Copyright (C) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
* Modifications Copyright (C) 2021 ARM, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
class NegativeDescriptorIndexing : public DescriptorIndexingTest {};
TEST_F(NegativeDescriptorIndexing, UpdateAfterBind) {
TEST_DESCRIPTION("Exercise errors for updating a descriptor set after it is bound.");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::fragmentStoresAndAtomics);
AddRequiredFeature(vkt::Feature::descriptorBindingStorageBufferUpdateAfterBind);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorBindingFlags flags[3] = {0, VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT};
VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = 3;
flags_create_info.pBindingFlags = &flags[0];
// Descriptor set has two bindings - only the second is update_after_bind
VkDescriptorSetLayoutBinding binding[3] = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&flags_create_info);
ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
ds_layout_ci.bindingCount = 3;
ds_layout_ci.pBindings = &binding[0];
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorPoolSize pool_sizes[3] = {
{binding[0].descriptorType, binding[0].descriptorCount},
{binding[1].descriptorType, binding[1].descriptorCount},
{binding[2].descriptorType, binding[2].descriptorCount},
};
VkDescriptorPoolCreateInfo dspci = vku::InitStructHelper();
dspci.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
dspci.poolSizeCount = 3;
dspci.pPoolSizes = &pool_sizes[0];
dspci.maxSets = 1;
vkt::DescriptorPool pool(*m_device, dspci);
VkDescriptorSetAllocateInfo ds_alloc_info = vku::InitStructHelper();
ds_alloc_info.descriptorPool = pool;
ds_alloc_info.descriptorSetCount = 1;
ds_alloc_info.pSetLayouts = &ds_layout.handle();
VkDescriptorSet ds = VK_NULL_HANDLE;
VkResult err = vk::AllocateDescriptorSets(*m_device, &ds_alloc_info, &ds);
ASSERT_EQ(VK_SUCCESS, err);
vkt::Buffer dynamic_uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
VkDescriptorBufferInfo buffInfo[2] = {};
buffInfo[0].buffer = dynamic_uniform_buffer;
buffInfo[0].offset = 0;
buffInfo[0].range = 1024;
VkWriteDescriptorSet descriptor_write[2] = {};
descriptor_write[0] = vku::InitStructHelper();
descriptor_write[0].dstSet = ds;
descriptor_write[0].dstBinding = 0;
descriptor_write[0].descriptorCount = 1;
descriptor_write[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write[0].pBufferInfo = buffInfo;
descriptor_write[1] = descriptor_write[0];
descriptor_write[1].dstBinding = 1;
descriptor_write[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
pipeline_layout_ci.setLayoutCount = 1;
pipeline_layout_ci.pSetLayouts = &ds_layout.handle();
vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
// Create a dummy pipeline, since VL inspects which bindings are actually used at draw time
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 color;
layout(set=0, binding=0) uniform foo0 { float x0; } bar0;
layout(set=0, binding=1) buffer foo1 { float x1; } bar1;
layout(set=0, binding=2) buffer foo2 { float x2; } bar2;
void main(){
color = vec4(bar0.x0 + bar1.x1 + bar2.x2);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
// Make both bindings valid before binding to the command buffer
vk::UpdateDescriptorSets(device(), 2, &descriptor_write[0], 0, NULL);
// Invalid to update binding 0 after being bound. But the error is actually
// generated during vk::EndCommandBuffer
vk::UpdateDescriptorSets(device(), 1, &descriptor_write[0], 0, NULL);
m_errorMonitor->SetDesiredError("VUID-vkEndCommandBuffer-commandBuffer-00059");
vk::EndCommandBuffer(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptorIndexing, SetNonIdenticalWrite) {
TEST_DESCRIPTION("VkWriteDescriptorSet must have identical VkDescriptorBindingFlagBits");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBindingStorageBufferUpdateAfterBind);
RETURN_IF_SKIP(Init());
// not all identical VkDescriptorBindingFlags flags
VkDescriptorBindingFlags flags[3] = {VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, 0,
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT};
VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = 3;
flags_create_info.pBindingFlags = &flags[0];
VkDescriptorSetLayoutBinding binding[3] = {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&flags_create_info);
ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
ds_layout_ci.bindingCount = 3;
ds_layout_ci.pBindings = &binding[0];
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorPoolSize pool_sizes = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3};
VkDescriptorPoolCreateInfo dspci = vku::InitStructHelper();
dspci.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
dspci.poolSizeCount = 1;
dspci.pPoolSizes = &pool_sizes;
dspci.maxSets = 3;
vkt::DescriptorPool pool(*m_device, dspci);
VkDescriptorSetAllocateInfo ds_alloc_info = vku::InitStructHelper();
ds_alloc_info.descriptorPool = pool;
ds_alloc_info.descriptorSetCount = 1;
ds_alloc_info.pSetLayouts = &ds_layout.handle();
VkDescriptorSet ds = VK_NULL_HANDLE;
ASSERT_EQ(VK_SUCCESS, vk::AllocateDescriptorSets(*m_device, &ds_alloc_info, &ds));
vkt::Buffer buffer(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
VkDescriptorBufferInfo bufferInfo[3] = {};
bufferInfo[0].buffer = buffer;
bufferInfo[0].offset = 0;
bufferInfo[0].range = 1024;
bufferInfo[1] = bufferInfo[0];
bufferInfo[2] = bufferInfo[0];
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = ds;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptor_write.pBufferInfo = bufferInfo;
// If the dstBinding has fewer than descriptorCount, remainder will be used to update the subsequent binding
descriptor_write.descriptorCount = 3;
// binding 1 has a different VkDescriptorBindingFlags
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorCount-10777");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptorIndexing, SetLayoutWithoutExtension) {
TEST_DESCRIPTION("Create an update_after_bind set layout without loading the needed extension.");
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
VkDescriptorSetLayout ds_layout = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-flags-parameter");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptorIndexing, SetLayout) {
TEST_DESCRIPTION("Exercise various create/allocate-time errors related to VK_EXT_descriptor_indexing.");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount);
RETURN_IF_SKIP(Init());
std::array<VkDescriptorBindingFlags, 2> flags = {
{VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT}};
VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = size32(flags);
flags_create_info.pBindingFlags = nullptr;
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&flags_create_info);
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &binding;
VkDescriptorSetLayout dsl = VK_NULL_HANDLE;
{
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-parameter");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &dsl);
m_errorMonitor->VerifyFound();
}
{
// VU for VkDescriptorSetLayoutBindingFlagsCreateInfo::bindingCount
flags_create_info.pBindingFlags = flags.data();
flags_create_info.bindingCount = 2;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-bindingCount-03002");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &dsl);
m_errorMonitor->VerifyFound();
}
flags_create_info.bindingCount = 1;
{
// set is missing UPDATE_AFTER_BIND_POOL flag.
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-flags-03000");
// binding uses a feature we disabled
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingUniformBufferUpdateAfterBind-03005");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &dsl);
m_errorMonitor->VerifyFound();
}
{
ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
ds_layout_ci.bindingCount = 0;
flags_create_info.bindingCount = 0;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorPoolSize pool_size = {binding.descriptorType, binding.descriptorCount};
VkDescriptorPoolCreateInfo dspci = vku::InitStructHelper();
dspci.poolSizeCount = 1;
dspci.pPoolSizes = &pool_size;
dspci.maxSets = 1;
vkt::DescriptorPool pool(*m_device, dspci);
VkDescriptorSetAllocateInfo ds_alloc_info = vku::InitStructHelper();
ds_alloc_info.descriptorPool = pool;
ds_alloc_info.descriptorSetCount = 1;
ds_alloc_info.pSetLayouts = &ds_layout.handle();
VkDescriptorSet ds = VK_NULL_HANDLE;
// mismatch between descriptor set and pool
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetAllocateInfo-pSetLayouts-03044");
vk::AllocateDescriptorSets(*m_device, &ds_alloc_info, &ds);
m_errorMonitor->VerifyFound();
}
// test descriptorBindingVariableDescriptorCount
{
VkDescriptorPoolSize pool_size = {binding.descriptorType, 3};
VkDescriptorPoolCreateInfo dspci = vku::InitStructHelper();
dspci.poolSizeCount = 1;
dspci.pPoolSizes = &pool_size;
dspci.maxSets = 2;
vkt::DescriptorPool pool(*m_device, dspci);
{
ds_layout_ci.flags = 0;
ds_layout_ci.bindingCount = 1;
flags_create_info.bindingCount = 1;
flags[0] = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorSetVariableDescriptorCountAllocateInfo count_alloc_info = vku::InitStructHelper();
count_alloc_info.descriptorSetCount = 1;
// Set variable count larger than what was in the descriptor binding
uint32_t variable_count = 2;
count_alloc_info.pDescriptorCounts = &variable_count;
VkDescriptorSetAllocateInfo ds_alloc_info = vku::InitStructHelper(&count_alloc_info);
ds_alloc_info.descriptorPool = pool;
ds_alloc_info.descriptorSetCount = 1;
ds_alloc_info.pSetLayouts = &ds_layout.handle();
VkDescriptorSet ds = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetAllocateInfo-pSetLayouts-09380");
vk::AllocateDescriptorSets(*m_device, &ds_alloc_info, &ds);
m_errorMonitor->VerifyFound();
}
{
// Now update descriptor set with a size that falls within the descriptor set layout size but that is more than the
// descriptor set size
binding.descriptorCount = 3;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorSetVariableDescriptorCountAllocateInfo count_alloc_info = vku::InitStructHelper();
count_alloc_info.descriptorSetCount = 1;
uint32_t variable_count = 2;
count_alloc_info.pDescriptorCounts = &variable_count;
VkDescriptorSetAllocateInfo ds_alloc_info = vku::InitStructHelper(&count_alloc_info);
ds_alloc_info.descriptorPool = pool;
ds_alloc_info.descriptorSetCount = 1;
ds_alloc_info.pSetLayouts = &ds_layout.handle();
VkDescriptorSet ds;
VkResult err = vk::AllocateDescriptorSets(*m_device, &ds_alloc_info, &ds);
ASSERT_EQ(VK_SUCCESS, err);
vkt::Buffer buffer(*m_device, 128 * 128, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buffer_info[3] = {};
for (int i = 0; i < 3; i++) {
buffer_info[i].buffer = buffer;
buffer_info[i].offset = 0;
buffer_info[i].range = 128 * 128;
}
VkWriteDescriptorSet descriptor_writes[1] = {};
descriptor_writes[0] = vku::InitStructHelper();
descriptor_writes[0].dstSet = ds;
descriptor_writes[0].dstBinding = 0;
descriptor_writes[0].descriptorCount = 3;
descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_writes[0].pBufferInfo = buffer_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
vk::UpdateDescriptorSets(device(), 1, descriptor_writes, 0, NULL);
m_errorMonitor->VerifyFound();
}
}
}
TEST_F(NegativeDescriptorIndexing, SetLayoutBindings) {
TEST_DESCRIPTION("Create descriptor set layout with incompatible bindings.");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBindingUniformBufferUpdateAfterBind);
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding update_binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorSetLayoutBinding dynamic_binding = {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorSetLayoutBinding bindings[2] = {update_binding, dynamic_binding};
VkDescriptorBindingFlags flags[2] = {VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, 0};
VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = 2;
flags_create_info.pBindingFlags = flags;
VkDescriptorSetLayoutCreateInfo create_info = vku::InitStructHelper(&flags_create_info);
create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
create_info.bindingCount = 2;
create_info.pBindings = bindings;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-03001");
VkDescriptorSetLayout set_layout;
vk::CreateDescriptorSetLayout(*m_device, &create_info, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptorIndexing, VariableDescriptorCount) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10370");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount);
RETURN_IF_SKIP(Init());
OneOffDescriptorIndexingSet descriptor_set(
m_device, {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr,
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT}});
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView image_view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstBinding-00316");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptorIndexing, DescriptorSetVariableDescriptorCountAllocateInfo) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10370");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount);
RETURN_IF_SKIP(Init());
m_errorMonitor->ExpectSuccess(kErrorBit | kWarningBit);
VkDescriptorBindingFlags binding_flags = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT;
VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = 1;
flags_create_info.pBindingFlags = &binding_flags;
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&flags_create_info);
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &binding;
ds_layout_ci.flags = 0;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorPoolSize pool_size = {binding.descriptorType, 3};
VkDescriptorPoolCreateInfo dspci = vku::InitStructHelper();
dspci.poolSizeCount = 1;
dspci.pPoolSizes = &pool_size;
dspci.maxSets = 2;
vkt::DescriptorPool pool(*m_device, dspci);
// forget VkDescriptorSetVariableDescriptorCountAllocateInfo
VkDescriptorSetAllocateInfo ds_alloc_info = vku::InitStructHelper();
ds_alloc_info.descriptorPool = pool;
ds_alloc_info.descriptorSetCount = 1;
ds_alloc_info.pSetLayouts = &ds_layout.handle();
VkDescriptorSet ds = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredWarning("WARNING-CoreValidation-AllocateDescriptorSets-VariableDescriptorCount");
vk::AllocateDescriptorSets(*m_device, &ds_alloc_info, &ds);
m_errorMonitor->VerifyFound();
VkDescriptorSetVariableDescriptorCountAllocateInfo count_alloc_info = vku::InitStructHelper();
count_alloc_info.descriptorSetCount = 1;
uint32_t variable_count = 0; // explicit, no warning
count_alloc_info.pDescriptorCounts = &variable_count;
ds_alloc_info.pNext = &count_alloc_info;
vk::AllocateDescriptorSets(*m_device, &ds_alloc_info, &ds);
}
TEST_F(NegativeDescriptorIndexing, VariableDescriptorCountBuffer) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10490");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount);
RETURN_IF_SKIP(Init());
vkt::Buffer buffer(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
VkDescriptorBindingFlags binding_flags = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT;
VkDescriptorSetLayoutBindingFlagsCreateInfo dsl_binding_flags = vku::InitStructHelper();
dsl_binding_flags.bindingCount = 1u;
dsl_binding_flags.pBindingFlags = &binding_flags;
uint32_t variable_count = 2u;
VkDescriptorSetVariableDescriptorCountAllocateInfo variable_count_info = vku::InitStructHelper();
variable_count_info.descriptorSetCount = 1u;
variable_count_info.pDescriptorCounts = &variable_count;
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
},
0u, &dsl_binding_flags, 0u, &variable_count_info);
descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0u, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0u);
descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0u, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
descriptor_set.UpdateDescriptorSets();
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char *cs_source = R"glsl(
#version 450 core
layout(set = 0, binding = 0) buffer SSBO { int x; } bufs[4];
void main() {
bufs[0].x = 0;
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.cp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-VkComputePipelineCreateInfo-layout-07991");
pipe.CreateComputePipeline();
m_errorMonitor->VerifyFound();
}