blob: 1afb41278dce406725f92dfa3e15b75f5ca31eb3 [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 <vulkan/vulkan_core.h>
#include "generated/vk_function_pointers.h"
#include "utils/cast_utils.h"
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
#include "../framework/descriptor_helper.h"
#include "../framework/render_pass_helper.h"
#include "../framework/ray_tracing_objects.h"
#include <algorithm>
class NegativeDescriptors : public VkLayerTest {};
TEST_F(NegativeDescriptors, DescriptorPoolConsistency) {
TEST_DESCRIPTION("Allocate descriptor sets from one DS pool and attempt to delete them from another.");
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_SAMPLER, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.flags = 0;
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool bad_pool(*m_device, ds_pool_ci);
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
m_errorMonitor->SetDesiredError("VUID-vkFreeDescriptorSets-pDescriptorSets-parent");
vk::FreeDescriptorSets(device(), bad_pool, 1, &descriptor_set.set_);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AllocDescriptorFromEmptyPool) {
TEST_DESCRIPTION("Attempt to allocate more sets and descriptors than descriptor pool has available.");
SetTargetApiVersion(VK_API_VERSION_1_0);
RETURN_IF_SKIP(Init());
// This test is valid for Vulkan 1.0 only -- skip if device has an API version greater than 1.0.
if (DeviceValidationVersion() >= VK_API_VERSION_1_1) {
GTEST_SKIP() << "Tests for 1.0 only";
}
// Create Pool w/ 1 Sampler descriptor, but try to alloc Uniform Buffer
// descriptor from it
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_SAMPLER, 2};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.flags = 0;
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
const vkt::DescriptorSetLayout ds_layout_samp(*m_device, {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr});
// Try to allocate 2 sets when pool only has 1 set
VkDescriptorSet descriptor_sets[2];
VkDescriptorSetLayout set_layouts[2] = {ds_layout_samp, ds_layout_samp};
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 2;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = set_layouts;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetAllocateInfo-apiVersion-07895");
vk::AllocateDescriptorSets(device(), &alloc_info, descriptor_sets);
m_errorMonitor->VerifyFound();
alloc_info.descriptorSetCount = 1;
// Create layout w/ descriptor type not available in pool
const vkt::DescriptorSetLayout ds_layout_ub(*m_device, {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr});
VkDescriptorSet descriptor_set;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &ds_layout_ub.handle();
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetAllocateInfo-apiVersion-07896");
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_set);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AllocateOverMaxSet) {
AddRequiredExtensions(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_SAMPLER, 2};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
const vkt::DescriptorSetLayout ds_layout(*m_device, {0, VK_DESCRIPTOR_TYPE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr});
VkDescriptorSet descriptor_sets[2];
VkDescriptorSetLayout set_layouts[2] = {ds_layout, ds_layout};
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 2;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = set_layouts;
m_errorMonitor->SetDesiredWarning("WARNING-VkDescriptorSetAllocateInfo-maxSet");
vk::AllocateDescriptorSets(device(), &alloc_info, descriptor_sets);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AllocateOverMaxSet2) {
AddRequiredExtensions(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_SAMPLER, 2};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
const vkt::DescriptorSetLayout ds_layout(*m_device, {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr});
VkDescriptorSet descriptor_sets[2];
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 1;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = &ds_layout.handle();
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_sets[0]);
vk::FreeDescriptorSets(device(), ds_pool, 1, &descriptor_sets[0]);
VkDescriptorSetLayout set_layouts[2] = {ds_layout, ds_layout};
alloc_info.descriptorSetCount = 2;
alloc_info.pSetLayouts = set_layouts;
m_errorMonitor->SetDesiredWarning("WARNING-VkDescriptorSetAllocateInfo-maxSet");
vk::AllocateDescriptorSets(device(), &alloc_info, descriptor_sets);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AllocateOverDescriptorCount) {
AddRequiredExtensions(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_counts[2] = {{VK_DESCRIPTOR_TYPE_SAMPLER, 2}, {VK_DESCRIPTOR_TYPE_SAMPLER, 2}};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 2;
ds_pool_ci.pPoolSizes = ds_type_counts;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
const vkt::DescriptorSetLayout ds_layout(*m_device, {0, VK_DESCRIPTOR_TYPE_SAMPLER, 5, VK_SHADER_STAGE_ALL, nullptr});
VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 1;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = &ds_layout.handle();
m_errorMonitor->SetDesiredWarning("WARNING-VkDescriptorSetAllocateInfo-descriptorCount");
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_set);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AllocateOverDescriptorCount2) {
AddRequiredExtensions(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_counts[2] = {{VK_DESCRIPTOR_TYPE_SAMPLER, 2}, {VK_DESCRIPTOR_TYPE_SAMPLER, 2}};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 3;
ds_pool_ci.poolSizeCount = 2;
ds_pool_ci.pPoolSizes = ds_type_counts;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_binding = {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr};
const vkt::DescriptorSetLayout ds_layout(*m_device, {dsl_binding});
dsl_binding.descriptorCount = 5;
const vkt::DescriptorSetLayout ds_layout_over(*m_device, {dsl_binding});
VkDescriptorSet descriptor_sets[3];
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 1;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = &ds_layout.handle();
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_sets[0]);
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_sets[1]);
alloc_info.pSetLayouts = &ds_layout_over.handle();
m_errorMonitor->SetDesiredWarning("WARNING-VkDescriptorSetAllocateInfo-descriptorCount");
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_sets[2]);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AllocateOverDescriptorCount3) {
AddRequiredExtensions(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_counts[2] = {{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 20}, {VK_DESCRIPTOR_TYPE_SAMPLER, 2}};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 4;
ds_pool_ci.poolSizeCount = 2;
ds_pool_ci.pPoolSizes = ds_type_counts;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_binding_sampler = {1, VK_DESCRIPTOR_TYPE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorSetLayoutBinding dsl_binding_buffer = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr};
const vkt::DescriptorSetLayout ds_layout_sampler(*m_device, {dsl_binding_buffer, dsl_binding_sampler});
const vkt::DescriptorSetLayout ds_layout_buffer(*m_device, {dsl_binding_buffer});
VkDescriptorSetLayout descriptor_set_layouts[4] = {ds_layout_sampler, ds_layout_buffer, ds_layout_sampler, ds_layout_sampler};
VkDescriptorSet descriptor_sets[4];
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorPool = ds_pool;
alloc_info.descriptorSetCount = 4;
alloc_info.pSetLayouts = descriptor_set_layouts;
m_errorMonitor->SetDesiredWarning("WARNING-VkDescriptorSetAllocateInfo-descriptorCount");
vk::AllocateDescriptorSets(device(), &alloc_info, descriptor_sets);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AllocateOverDescriptorCountVariableAllocate) {
AddRequiredExtensions(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount);
RETURN_IF_SKIP(Init());
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 bindings = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 32, VK_SHADER_STAGE_COMPUTE_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 = 1;
ds_layout_ci.pBindings = &bindings;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorPoolSize pool_sizes = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 8};
VkDescriptorPoolCreateInfo dspci = vku::InitStructHelper();
dspci.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
dspci.poolSizeCount = 1;
dspci.pPoolSizes = &pool_sizes;
dspci.maxSets = 1;
vkt::DescriptorPool pool(*m_device, dspci);
uint32_t desc_counts = 10;
VkDescriptorSetVariableDescriptorCountAllocateInfo variable_count = vku::InitStructHelper();
variable_count.descriptorSetCount = 1;
variable_count.pDescriptorCounts = &desc_counts;
VkDescriptorSetAllocateInfo ds_alloc_info = vku::InitStructHelper(&variable_count);
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-VkDescriptorSetAllocateInfo-descriptorCount");
vk::AllocateDescriptorSets(device(), &ds_alloc_info, &ds);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AllocateOverDescriptorYCbCr) {
SetTargetApiVersion(VK_API_VERSION_1_4); // Has VK_KHR_maintenance6
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceMaintenance6PropertiesKHR maintenance6_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(maintenance6_props);
if (maintenance6_props.maxCombinedImageSamplerDescriptorCount == 1) {
GTEST_SKIP() << "maxCombinedImageSamplerDescriptorCount is not over 1";
}
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
// Simple mistake, thinking this is only 1, but is really 3 on most implementations (one for each plane)
VkDescriptorPoolSize pool_size{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1};
VkDescriptorPoolCreateInfo pool_ci = vku::InitStructHelper();
pool_ci.flags = 0;
pool_ci.maxSets = 1;
pool_ci.poolSizeCount = 1;
pool_ci.pPoolSizes = &pool_size;
vkt::DescriptorPool pool(*m_device, pool_ci);
vkt::DescriptorSetLayout dsl(
*m_device, {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()});
VkDescriptorSetAllocateInfo ds_alloc_info = vku::InitStructHelper();
ds_alloc_info.descriptorPool = pool;
ds_alloc_info.descriptorSetCount = 1;
ds_alloc_info.pSetLayouts = &dsl.handle();
VkDescriptorSet ds = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredWarning("WARNING-VkDescriptorSetAllocateInfo-descriptorCount");
vk::AllocateDescriptorSets(device(), &ds_alloc_info, &ds);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, FreeDescriptorFromOneShotPool) {
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.flags = 0;
// Not specifying VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT means
// app can only call vk::ResetDescriptorPool on this pool.;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
const vkt::DescriptorSetLayout ds_layout(*m_device, {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr});
VkDescriptorSet descriptorSet;
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 1;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = &ds_layout.handle();
VkResult err = vk::AllocateDescriptorSets(device(), &alloc_info, &descriptorSet);
ASSERT_EQ(VK_SUCCESS, err);
m_errorMonitor->SetDesiredError("VUID-vkFreeDescriptorSets-descriptorPool-00312");
vk::FreeDescriptorSets(device(), ds_pool, 1, &descriptorSet);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorPool) {
// Attempt to clear Descriptor Pool with bad object.
// ObjectTracker should catch this.
RETURN_IF_SKIP(Init());
m_errorMonitor->SetDesiredError("VUID-vkResetDescriptorPool-descriptorPool-parameter");
constexpr uint64_t fake_pool_handle = 0xbaad6001;
VkDescriptorPool bad_pool = CastFromUint64<VkDescriptorPool>(fake_pool_handle);
vk::ResetDescriptorPool(device(), bad_pool, 0);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, BindInvalidDescriptorSet) {
RETURN_IF_SKIP(Init());
constexpr uint64_t fake_set_handle = 0xbaad6001;
VkDescriptorSet bad_set = CastFromUint64<VkDescriptorSet>(fake_set_handle);
const vkt::DescriptorSetLayout descriptor_set_layout(
*m_device, {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_layout});
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-parameter");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &bad_set, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorSetNotInRange) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_, &descriptor_set.layout_});
VkDescriptorSet descriptor_set_handles[4] = {descriptor_set.set_, descriptor_set.set_, descriptor_set.set_,
descriptor_set.set_};
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-firstSet-00360");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 3u, descriptor_set_handles,
0u, nullptr);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-firstSet-00360");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 2u, 1u, descriptor_set_handles,
0u, nullptr);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-firstSet-00360");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 1u, 2u, descriptor_set_handles,
0u, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorSetNotInRange2) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_6_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance6);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_, &descriptor_set.layout_});
VkDescriptorSet descriptor_set_handles[4] = {descriptor_set.set_, descriptor_set.set_, descriptor_set.set_,
descriptor_set.set_};
VkBindDescriptorSetsInfo bind_ds_info = vku::InitStructHelper();
bind_ds_info.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bind_ds_info.layout = pipeline_layout;
bind_ds_info.pDescriptorSets = descriptor_set_handles;
bind_ds_info.dynamicOffsetCount = 0;
bind_ds_info.pDynamicOffsets = nullptr;
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-VkBindDescriptorSetsInfo-firstSet-00360");
bind_ds_info.firstSet = 0;
bind_ds_info.descriptorSetCount = 3;
vk::CmdBindDescriptorSets2KHR(m_command_buffer, &bind_ds_info);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-VkBindDescriptorSetsInfo-firstSet-00360");
bind_ds_info.firstSet = 2;
bind_ds_info.descriptorSetCount = 1;
vk::CmdBindDescriptorSets2KHR(m_command_buffer, &bind_ds_info);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-VkBindDescriptorSetsInfo-firstSet-00360");
bind_ds_info.firstSet = 1;
bind_ds_info.descriptorSetCount = 2;
vk::CmdBindDescriptorSets2KHR(m_command_buffer, &bind_ds_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, IncompatiblePipelineLayout) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
OneOffDescriptorSet descriptor_set_bad(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout_bad(*m_device, {&descriptor_set_bad.layout_});
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_bad, 0u, 1u, &descriptor_set.set_,
0u, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, IncompatiblePipelineLayout2) {
RETURN_IF_SKIP(Init());
if (m_device->Physical().limits_.maxPerStageDescriptorStorageBuffers <= 8) {
GTEST_SKIP() << "maxPerStageDescriptorStorageBuffers of 8+ required";
}
OneOffDescriptorSet descriptor_set1(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
OneOffDescriptorSet descriptor_set2(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set1.layout_, &descriptor_set1.layout_, &descriptor_set1.layout_});
VkDescriptorSet descriptor_set_handles[2] = {descriptor_set1.set_, descriptor_set2.set_};
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 1u, 2u, descriptor_set_handles,
0u, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, NullDescriptorSetGPL) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10312");
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary);
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding dsl_binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dsl_binding;
vkt::DescriptorSetLayout ds_layout_a(*m_device, ds_layout_ci);
ds_layout_ci.bindingCount = 0;
ds_layout_ci.pBindings = nullptr;
vkt::DescriptorSetLayout ds_layout_empty(*m_device, ds_layout_ci);
VkDescriptorPoolSize pool_size = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 2;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &pool_size;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 1;
allocate_info.pSetLayouts = &ds_layout_a.handle();
VkDescriptorSet descriptor_set_a = VK_NULL_HANDLE;
vk::AllocateDescriptorSets(device(), &allocate_info, &descriptor_set_a);
allocate_info.pSetLayouts = &ds_layout_empty.handle();
VkDescriptorSet descriptor_set_empty = VK_NULL_HANDLE;
vk::AllocateDescriptorSets(device(), &allocate_info, &descriptor_set_empty);
VkDescriptorSetLayout dsl_handles[2] = {VK_NULL_HANDLE, ds_layout_a};
VkPipelineLayoutCreateInfo pipe_layout_ci = vku::InitStructHelper();
pipe_layout_ci.setLayoutCount = 2;
pipe_layout_ci.pSetLayouts = dsl_handles;
vkt::PipelineLayout pipeline_layout(*m_device, pipe_layout_ci);
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358");
VkDescriptorSet descriptor_set_handles[2] = {descriptor_set_empty, descriptor_set_a};
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 2u, descriptor_set_handles,
0u, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DescriptorSetLayout) {
// Attempt to create a Pipeline Layout with an invalid Descriptor Set Layout.
// ObjectTracker should catch this.
constexpr uint64_t fake_layout_handle = 0xbaad6001;
VkDescriptorSetLayout bad_layout = CastFromUint64<VkDescriptorSetLayout>(fake_layout_handle);
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-pSetLayouts-parameter");
RETURN_IF_SKIP(Init());
VkPipelineLayout pipeline_layout;
VkPipelineLayoutCreateInfo plci = vku::InitStructHelper();
plci.setLayoutCount = 1;
plci.pSetLayouts = &bad_layout;
vk::CreatePipelineLayout(device(), &plci, NULL, &pipeline_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetNullBufferInfo) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = nullptr;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00324");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetTypeStageMatch) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{4, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}});
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buffer_infos[5] = {};
for (int i = 0; i < 5; ++i) {
buffer_infos[i] = {uniform_buffer, 0, VK_WHOLE_SIZE};
}
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = buffer_infos;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 2;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorCount-00317");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 2;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 5;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorCount-10776");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstArrayElement = 1;
descriptor_write.descriptorCount = 4;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorCount-10776");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetImmutableSamplerMix) {
RETURN_IF_SKIP(Init());
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
OneOffDescriptorSet descriptor_set(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler.handle()}});
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 2;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
VkDescriptorImageInfo image_infos[2] = {
{sampler, image_view, VK_IMAGE_LAYOUT_GENERAL},
{VK_NULL_HANDLE, image_view, VK_IMAGE_LAYOUT_GENERAL},
};
descriptor_write.pImageInfo = image_infos;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorCount-00318");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetIntegrity) {
RETURN_IF_SKIP(Init());
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
OneOffDescriptorSet descriptor_set(m_device,
{{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()},
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{4, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}});
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.descriptorCount = 1;
descriptor_write.dstArrayElement = 0;
// Attmept write with incorrect layout for sampled descriptor
VkDescriptorImageInfo image_info = {VK_NULL_HANDLE, image_view, VK_IMAGE_LAYOUT_UNDEFINED};
descriptor_write.pImageInfo = &image_info;
descriptor_write.dstBinding = 2;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-04149");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 3;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
image_info.sampler = sampler;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-04150");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 4;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-04151");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetInputAttachment) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11098");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
const VkFormat depth_format = FindSupportedDepthOnlyFormat(Gpu());
vkt::Image depth_image(*m_device, 8, 8, depth_format, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
vkt::ImageView image_view = depth_image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT);
VkDescriptorImageInfo image_info = {VK_NULL_HANDLE, image_view, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL};
OneOffDescriptorSet descriptor_set(m_device,
{{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}});
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.descriptorCount = 1;
descriptor_write.dstArrayElement = 0;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
descriptor_write.pImageInfo = &image_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-04151");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetInputAttachment2) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_ARM_TENSORS_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
vkt::Image image(*m_device, 8, 8, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
VkDescriptorImageInfo image_info = {VK_NULL_HANDLE, image_view, VK_IMAGE_LAYOUT_TENSOR_ALIASING_ARM};
OneOffDescriptorSet descriptor_set(m_device,
{{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}});
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.descriptorCount = 1;
descriptor_write.dstArrayElement = 0;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
descriptor_write.pImageInfo = &image_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-04151");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteImmutableSampler) {
RETURN_IF_SKIP(Init());
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()},
});
descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02752");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteImmutableSampler2) {
RETURN_IF_SKIP(Init());
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()},
});
VkDescriptorImageInfo image_info[2] = {{sampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_GENERAL},
{sampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_GENERAL}};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 2;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptor_write.pImageInfo = image_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorCount-00318");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetIdentitySwizzle) {
TEST_DESCRIPTION("Test descriptors that need to have identity swizzle set");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::Image image(*m_device, 64, 64, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
VkImageViewCreateInfo image_view_ci = vku::InitStructHelper();
image_view_ci.image = image;
image_view_ci.format = VK_FORMAT_R8G8B8A8_UNORM;
image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
image_view_ci.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
// G and B are swizzled
image_view_ci.components.r = VK_COMPONENT_SWIZZLE_R;
image_view_ci.components.g = VK_COMPONENT_SWIZZLE_B;
image_view_ci.components.b = VK_COMPONENT_SWIZZLE_G;
image_view_ci.components.a = VK_COMPONENT_SWIZZLE_A;
vkt::ImageView image_view(*m_device, image_view_ci);
descriptor_set.WriteDescriptorImageInfo(0, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00336");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetConsecutiveUpdates) {
TEST_DESCRIPTION(
"Verifies that updates rolling over to next descriptor work correctly by destroying buffer from consecutive update known "
"to be used in descriptor set and verifying that error is flagged.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Buffer buffer0(*m_device, 2048, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
CreatePipelineHelper pipe(*this);
{ // Scope 2nd buffer to cause early destruction
vkt::Buffer buffer1(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buffer_info[3] = {
{buffer0, 0, 1024},
{buffer0, 1024, 1024},
{buffer1, 0, 1024},
};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_; // descriptor_set;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 3;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = buffer_info;
// Update descriptor
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
// Create PSO that uses the uniform buffers
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(set=0) layout(binding=0) uniform foo { int x; int y; } bar;
layout(set=0) layout(binding=1) uniform blah { int x; } duh;
void main(){
x = vec4(duh.x, bar.y, bar.x, 1);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&descriptor_set.layout_});
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1,
&descriptor_set.set_, 0, nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
// buffer2 just went out of scope and was destroyed
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->Submit(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, CmdBufferDescriptorSetBufferDestroyed) {
TEST_DESCRIPTION(
"Attempt to draw with a command buffer that is invalid due to a bound descriptor set with a buffer dependency being "
"destroyed.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
{
// Create a buffer to update the descriptor with
vkt::Buffer buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// Create PSO to be used for draw-time errors below
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(set=0) layout(binding=0) uniform foo { int x; int y; } bar;
void main(){
x = vec4(bar.y);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
// Correctly update descriptor to avoid "NOT_UPDATED" error
pipe.descriptor_set_->WriteDescriptorBufferInfo(0, buffer, 0, 1024);
pipe.descriptor_set_->UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_->set_, 0, NULL);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
// Destroy buffer should invalidate the cmd buffer, causing error on submit
// Attempt to submit cmd buffer
// Invalid VkBuffer
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->Submit(m_command_buffer);
m_errorMonitor->VerifyFound();
}
// This is similar to the CmdBufferDescriptorSetBufferDestroyed test above except that the buffer
// is destroyed before recording the Draw cmd.
TEST_F(NegativeDescriptors, DrawDescriptorSetBufferDestroyed) {
TEST_DESCRIPTION("Attempt to bind a descriptor set that is invalid at Draw time due to its buffer dependency being destroyed.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
{
// Create a buffer to update the descriptor with
vkt::Buffer buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// Create PSO to be used for draw-time errors below
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(set=0) layout(binding=0) uniform foo { int x; int y; } bar;
void main(){
x = vec4(bar.y);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
// Correctly update descriptor to avoid "NOT_UPDATED" error
pipe.descriptor_set_->WriteDescriptorBufferInfo(0, buffer, 0, 1024);
pipe.descriptor_set_->UpdateDescriptorSets();
}
// The buffer has now been destroyed, but it has been written into the descriptor set.
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_->set_, 0, NULL);
// Invalid VkBuffer - The check is made at Draw time.
m_errorMonitor->SetDesiredError("that is invalid or has been destroyed");
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, CmdBufferDescriptorSetImageSamplerDestroyed) {
TEST_DESCRIPTION(
"Attempt to draw with a command buffer that is invalid due to a bound descriptor sets with a combined image sampler having "
"their image, sampler, and descriptor set each respectively destroyed and then attempting to submit associated cmd "
"buffers. Attempt to destroy a DescriptorSet that is in use.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}},
0, nullptr, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT);
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
// Create images to update the descriptor with
const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
auto image_create_info = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, tex_format, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::Image tmp_image(*m_device, image_create_info, vkt::no_mem);
vkt::Image image2(*m_device, image_create_info, vkt::no_mem);
VkMemoryRequirements memory_reqs;
bool pass;
VkMemoryAllocateInfo memory_info = vku::InitStructHelper();
memory_info.allocationSize = 0;
memory_info.memoryTypeIndex = 0;
vk::GetImageMemoryRequirements(device(), tmp_image, &memory_reqs);
// Allocate enough memory for both images
VkDeviceSize align_mod = memory_reqs.size % memory_reqs.alignment;
VkDeviceSize aligned_size = ((align_mod == 0) ? memory_reqs.size : (memory_reqs.size + memory_reqs.alignment - align_mod));
memory_info.allocationSize = aligned_size * 2;
pass = m_device->Physical().SetMemoryType(memory_reqs.memoryTypeBits, &memory_info, 0);
ASSERT_TRUE(pass);
vkt::DeviceMemory image_memory(*m_device, memory_info);
tmp_image.BindMemory(image_memory, 0);
// Bind second image to memory right after first image
image2.BindMemory(image_memory, aligned_size);
// First test deletes this view
vkt::ImageView tmp_view = tmp_image.CreateView();
vkt::ImageView view = tmp_image.CreateView();
vkt::ImageView view2 = image2.CreateView();
vkt::Sampler tmp_sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Sampler sampler2(*m_device, SafeSaneSamplerCreateInfo());
VkDescriptorImageInfo img_info = {tmp_sampler, tmp_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.pImageInfo = &img_info;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
// Create PSO to be used for draw-time errors below
const char *fsSource = R"glsl(
#version 450
layout(set=0, binding=0) uniform sampler2D s;
layout(location=0) out vec4 x;
void main(){
x = texture(s, vec2(1));
}
)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();
// First error case is destroying sampler prior to cmd buffer submission
m_command_buffer.Begin();
// Transit image layout from VK_IMAGE_LAYOUT_UNDEFINED into VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
VkImageMemoryBarrier barrier = vku::InitStructHelper();
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = tmp_image;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
barrier.subresourceRange.layerCount = 1;
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr,
0, nullptr, 1, &barrier);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
// This first submit should be successful
m_default_queue->SubmitAndWait(m_command_buffer);
// Now destroy imageview and reset cmdBuffer
tmp_view.Destroy();
m_command_buffer.Reset(0);
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
m_errorMonitor->SetDesiredError(" that is invalid or has been destroyed.");
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
// Re-update descriptor with new view
img_info.imageView = view;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
// Now test destroying sampler prior to cmd buffer submission
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
// Destroy sampler invalidates the cmd buffer, causing error on submit
tmp_sampler.Destroy();
// Attempt to submit cmd buffer
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->Submit(m_command_buffer);
m_errorMonitor->VerifyFound();
// Now re-update descriptor with valid sampler and delete image
img_info.sampler = sampler2;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
VkCommandBufferBeginInfo info = vku::InitStructHelper();
info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_command_buffer.Begin(&info);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
// Destroy image invalidates the cmd buffer, causing error on submit
tmp_image.Destroy();
// Attempt to submit cmd buffer
m_default_queue->Submit(m_command_buffer);
m_errorMonitor->VerifyFound();
// Now update descriptor to be valid, but then update and free descriptor
img_info.imageView = view2;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_command_buffer.Begin(&info);
// Transit image2 layout from VK_IMAGE_LAYOUT_UNDEFINED into VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
barrier.image = image2;
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr,
0, nullptr, 1, &barrier);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
// Immediately try to update the descriptor set in the active command buffer - failure expected
m_errorMonitor->SetDesiredError("VUID-vkUpdateDescriptorSets-None-03047");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
// Immediately try to destroy the descriptor set in the active command buffer - failure expected
m_errorMonitor->SetDesiredError("VUID-vkFreeDescriptorSets-pDescriptorSets-00309");
vk::FreeDescriptorSets(device(), descriptor_set.pool_, 1, &descriptor_set.set_);
m_errorMonitor->VerifyFound();
// Try again once the queue is idle - should succeed w/o error
// TODO - though the particular error above doesn't re-occur, there are other 'unexpecteds' still to clean up
m_default_queue->Wait();
m_errorMonitor->SetUnexpectedError(
"pDescriptorSets must be a valid pointer to an array of descriptorSetCount VkDescriptorSet handles, each element of which "
"must either be a valid handle or VK_NULL_HANDLE");
m_errorMonitor->SetUnexpectedError("Unable to remove DescriptorSet obj");
vk::FreeDescriptorSets(device(), descriptor_set.pool_, 1, &descriptor_set.set_);
// Attempt to submit cmd buffer containing the freed descriptor set
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->Submit(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, OpArrayLengthStaticallyUsed) {
TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/7137");
SetTargetApiVersion(VK_API_VERSION_1_2);
RETURN_IF_SKIP(Init());
m_errorMonitor->ExpectSuccess(kErrorBit | kWarningBit | kInformationBit);
const char *shader_source = R"glsl(
#version 450
#extension GL_EXT_debug_printf : enable
layout(set = 0, binding = 0) buffer SSBO_0 {
uint a;
};
layout(set = 1, binding = 0) buffer SSBO_1 {
uint b;
vec4 c[];
};
void main() {
// length() here is consider static usage of the descriptor
a = c.length();
}
)glsl";
vkt::Buffer buffer(*m_device, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
OneOffDescriptorSet descriptor_set0(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
OneOffDescriptorSet descriptor_set1(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set0.layout_, &descriptor_set1.layout_});
descriptor_set0.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set0.UpdateDescriptorSets();
descriptor_set1.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set1.UpdateDescriptorSets();
CreateComputePipelineHelper pipe(*this);
pipe.cp_ci_.layout = pipeline_layout;
pipe.cs_ = VkShaderObj(*m_device, shader_source, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.CreateComputePipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set0.set_, 0,
nullptr);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 1, 1, &descriptor_set1.set_, 0,
nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
descriptor_set1.UpdateDescriptorSets(); // command buffer is invalid now
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorSetSamplerDestroyed) {
TEST_DESCRIPTION("Attempt to draw with a bound descriptor sets with a combined image sampler where sampler has been deleted.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
// Create images to update the descriptor with
const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
vkt::Image image(*m_device, 32, 32, tex_format, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView view = image.CreateView();
VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
vkt::Sampler sampler(*m_device, sampler_ci);
vkt::Sampler sampler1(*m_device, sampler_ci);
descriptor_set.WriteDescriptorImageInfo(0, view, sampler);
descriptor_set.WriteDescriptorImageInfo(1, view, sampler1);
descriptor_set.UpdateDescriptorSets();
// Destroy the sampler before it's bound to the cmd buffer
sampler1.Destroy();
// Create PSO to be used for draw-time errors below
const char *fsSource = R"glsl(
#version 450
layout(set=0, binding=0) uniform sampler2D s;
layout(set=0, binding=1) uniform sampler2D s1;
layout(location=0) out vec4 x;
void main(){
x = texture(s, vec2(1));
x = texture(s1, vec2(1));
}
)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();
// First error case is destroying sampler prior to cmd buffer submission
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
NULL);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08114");
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, ImageDescriptorLayoutMismatch) {
TEST_DESCRIPTION("Create an image sampler layout->image layout mismatch within/without a command buffer");
AddOptionalExtensions(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const bool maintenance2 = IsExtensionsEnabled(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
VkDescriptorSet descriptorSet = descriptor_set.set_;
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
// Create image, view, and sampler
const VkFormat format = VK_FORMAT_B8G8R8A8_UNORM;
vkt::Image image(*m_device, 32, 32, format, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
auto image_view_create_info = image.BasicViewCreatInfo();
vkt::ImageView view(*m_device, image_view_create_info);
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
// Setup structure for descriptor update with sampler, for update in do_test below
VkDescriptorImageInfo img_info = {sampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptorSet;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.pImageInfo = &img_info;
// Create PSO to be used for draw-time errors below
VkShaderObj fs(*m_device, kFragmentSamplerGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
vkt::CommandBuffer cmd_buf(*m_device, m_command_pool);
enum TestType {
kInternal, // Image layout mismatch is *within* a given command buffer
kExternal // Image layout mismatch is with the current state of the image, found at QueueSubmit
};
constexpr std::array test_list = {kInternal, kExternal};
constexpr std::array internal_errors = {"VUID-vkCmdDraw-imageLayout-00344"};
constexpr std::array external_errors = {"VUID-vkCmdDraw-None-09600"};
// Common steps to create the two classes of errors (or two classes of positives)
auto do_test = [&](vkt::Image *image, vkt::ImageView *view, VkImageAspectFlags aspect_mask, VkImageLayout image_layout,
VkImageLayout descriptor_layout, const bool positive_test) {
// Set up the descriptor
img_info.imageView = view->handle();
img_info.imageLayout = descriptor_layout;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
for (TestType test_type : test_list) {
cmd_buf.Begin();
// record layout different than actual descriptor layout.
const VkFlags read_write = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
const VkImageSubresourceRange range = image->SubresourceRange(aspect_mask);
auto image_barrier = image->ImageMemoryBarrier(read_write, read_write, VK_IMAGE_LAYOUT_UNDEFINED, image_layout, range);
vk::CmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, 0, nullptr,
0, nullptr, 1, &image_barrier);
if (test_type == kExternal) {
// The image layout is external to the command buffer we are recording to test. Submit to push to instance scope.
cmd_buf.End();
m_default_queue->Submit(cmd_buf);
m_default_queue->Wait();
cmd_buf.Begin();
}
cmd_buf.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptorSet, 0, NULL);
// At draw time the update layout will mis-match the actual layout
if (positive_test || (test_type == kExternal)) {
} else {
for (const auto &err : internal_errors) {
m_errorMonitor->SetDesiredError(err);
}
}
vk::CmdDraw(cmd_buf, 1, 0, 0, 0);
if (positive_test || (test_type == kExternal)) {
} else {
m_errorMonitor->VerifyFound();
}
cmd_buf.EndRenderPass();
cmd_buf.End();
// Submit cmd buffer
if (positive_test || (test_type == kInternal)) {
} else {
for (const auto &err : external_errors) {
m_errorMonitor->SetDesiredError(err);
}
}
m_default_queue->Submit(cmd_buf);
m_default_queue->Wait();
if (positive_test || (test_type == kInternal)) {
} else {
m_errorMonitor->VerifyFound();
}
}
};
do_test(&image, &view, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, /* positive */ false);
// Create depth stencil image and views
const VkFormat format_ds = m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu());
bool ds_test_support = maintenance2 && (format_ds != VK_FORMAT_UNDEFINED);
const VkImageLayout ds_image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
const VkImageLayout depth_descriptor_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
const VkImageLayout stencil_descriptor_layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
const VkImageAspectFlags depth_stencil = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
if (ds_test_support) {
vkt::Image image_ds(*m_device, 32, 32, format_ds, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
auto ds_view_ci = image_ds.BasicViewCreatInfo(VK_IMAGE_ASPECT_DEPTH_BIT);
vkt::ImageView depth_view(*m_device, ds_view_ci);
ds_view_ci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
vkt::ImageView stencil_view(*m_device, ds_view_ci);
do_test(&image_ds, &depth_view, depth_stencil, ds_image_layout, depth_descriptor_layout, /* positive */ true);
do_test(&image_ds, &depth_view, depth_stencil, ds_image_layout, VK_IMAGE_LAYOUT_GENERAL, /* positive */ false);
do_test(&image_ds, &stencil_view, depth_stencil, ds_image_layout, stencil_descriptor_layout, /* positive */ true);
do_test(&image_ds, &stencil_view, depth_stencil, ds_image_layout, VK_IMAGE_LAYOUT_GENERAL, /* positive */ false);
}
}
TEST_F(NegativeDescriptors, DescriptorPoolInUseResetSignaled) {
TEST_DESCRIPTION("Reset a DescriptorPool with a DescriptorSet that is in use.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
// Create image to update the descriptor with
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkt::ImageView view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
// Update descriptor with image and sampler
descriptor_set.WriteDescriptorImageInfo(0, view, sampler);
descriptor_set.UpdateDescriptorSets();
// Create PSO to be used for draw-time errors below
VkShaderObj fs(*m_device, kFragmentSamplerGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
// Submit cmd buffer to put pool in-flight
m_default_queue->Submit(m_command_buffer);
// Reset pool while in-flight, causing error
m_errorMonitor->SetDesiredError("VUID-vkResetDescriptorPool-descriptorPool-00313");
vk::ResetDescriptorPool(device(), descriptor_set.pool_, 0);
m_errorMonitor->VerifyFound();
m_default_queue->Wait();
}
TEST_F(NegativeDescriptors, DescriptorImageUpdateNoMemoryBound) {
TEST_DESCRIPTION("Attempt an image descriptor set update where image's bound memory has been freed.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
// Create images to update the descriptor with
const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
auto image_create_info = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, tex_format, VK_IMAGE_USAGE_SAMPLED_BIT);
// Create with bound memory to avoid error at bind view time. We'll break binding before update.
vkt::Image image(*m_device, image_create_info);
vkt::ImageView view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
// Update descriptor with image and sampler
descriptor_set.WriteDescriptorImageInfo(0, view, sampler);
// Break memory binding and attempt update
image.Memory().Destroy();
m_errorMonitor->SetDesiredError("UNASSIGNED-VkDescriptorImageInfo-BoundResourceFreedMemoryAccess");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DynamicOffsetCases) {
// Create a descriptorSet w/ dynamic descriptor and then hit 3 offset error
// cases:
// 1. No dynamicOffset supplied
// 2. Too many dynamicOffsets supplied
// 3. Dynamic offset oversteps buffer being updated
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
// Create a buffer to update the descriptor with
vkt::Buffer dynamic_uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// Correctly update descriptor to avoid "NOT_UPDATED" error
descriptor_set.WriteDescriptorBufferInfo(0, dynamic_uniform_buffer, 0, 1024, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
descriptor_set.UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
m_errorMonitor->VerifyFound();
uint32_t pDynOff[2] = {0, 756};
// Now cause error b/c too many dynOffsets in array for # of dyn descriptors
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 2,
pDynOff);
m_errorMonitor->VerifyFound();
pDynOff[0] = 512;
// Finally cause error due to dynamicOffset being too big
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979");
// Create PSO to be used for draw-time errors below
VkShaderObj fs(*m_device, kFragmentUniformGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
// This update should succeed, but offset size of 512 will overstep buffer
// /w range 1024 & size 1024
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 1,
pDynOff);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DynamicOffsetCasesMaintenance6) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_6_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance6);
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
vkt::Buffer dynamic_uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// Correctly update descriptor to avoid "NOT_UPDATED" error
descriptor_set.WriteDescriptorBufferInfo(0, dynamic_uniform_buffer, 0, 1024, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
descriptor_set.UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
VkBindDescriptorSetsInfo bind_ds_info = vku::InitStructHelper();
bind_ds_info.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bind_ds_info.layout = pipeline_layout;
bind_ds_info.firstSet = 0;
bind_ds_info.descriptorSetCount = 1;
bind_ds_info.pDescriptorSets = &descriptor_set.set_;
bind_ds_info.dynamicOffsetCount = 0;
bind_ds_info.pDynamicOffsets = nullptr;
m_errorMonitor->SetDesiredError("VUID-VkBindDescriptorSetsInfo-dynamicOffsetCount-00359");
vk::CmdBindDescriptorSets2KHR(m_command_buffer, &bind_ds_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, BindDescriptorSetsInfoPipelineLayout) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_6_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance6);
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Buffer dynamic_uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// Correctly update descriptor to avoid "NOT_UPDATED" error
descriptor_set.WriteDescriptorBufferInfo(0, dynamic_uniform_buffer, 0, 1024, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
descriptor_set.UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
VkBindDescriptorSetsInfo bind_ds_info = vku::InitStructHelper();
bind_ds_info.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bind_ds_info.layout = CastToHandle<VkPipelineLayout, uintptr_t>(0xbaadb1be);
bind_ds_info.firstSet = 0;
bind_ds_info.descriptorSetCount = 1;
bind_ds_info.pDescriptorSets = &descriptor_set.set_;
bind_ds_info.dynamicOffsetCount = 0;
bind_ds_info.pDynamicOffsets = nullptr;
m_errorMonitor->SetDesiredError("VUID-VkBindDescriptorSetsInfo-layout-parameter");
vk::CmdBindDescriptorSets2KHR(m_command_buffer, &bind_ds_info);
m_errorMonitor->VerifyFound();
bind_ds_info.layout = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkBindDescriptorSetsInfo-None-09495");
vk::CmdBindDescriptorSets2KHR(m_command_buffer, &bind_ds_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorBufferUpdateNoMemoryBound) {
TEST_DESCRIPTION("Attempt to update a descriptor with a non-sparse buffer that doesn't have memory bound");
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00329");
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr},
});
// Create a buffer to update the descriptor with
VkBufferCreateInfo buffCI = vku::InitStructHelper();
buffCI.size = 1024;
buffCI.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
vkt::Buffer dynamic_uniform_buffer(*m_device, buffCI, vkt::no_mem);
// Attempt to update descriptor without binding memory to it
descriptor_set.WriteDescriptorBufferInfo(0, dynamic_uniform_buffer, 0, 1024, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DynamicDescriptorSet) {
RETURN_IF_SKIP(Init());
const VkDeviceSize partial_size = m_device->Physical().limits_.minUniformBufferOffsetAlignment;
const VkDeviceSize buffer_size = partial_size * 10; // make sure way more then alignment multiple
// Create a buffer to update the descriptor with
vkt::Buffer buffer(*m_device, buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// test various uses of offsets and size
// The non-dynamic binds are there to make sure pDynamicOffsets are matched correctly at bind time
// clang-format off
OneOffDescriptorSet descriptor_set_0(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
// Gap to ensure looping for binding index is correct
{2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr} // pDynamicOffsets[0]
});
OneOffDescriptorSet descriptor_set_1(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
// This dynamic type has a descriptorCount of 0 which will be skipped
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 0, VK_SHADER_STAGE_ALL, nullptr},
});
OneOffDescriptorSet descriptor_set_2(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr}, // pDynamicOffsets[1]
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
// [2] and [3] are same, but tests descriptor arrays
{2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 2, VK_SHADER_STAGE_ALL, nullptr}, // pDynamicOffsets[2]/[3]
{3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr} // pDynamicOffsets[4]
});
// clang-format on
const vkt::PipelineLayout pipeline_layout(*m_device,
{&descriptor_set_0.layout_, &descriptor_set_1.layout_, &descriptor_set_2.layout_});
const VkPipelineLayout layout = pipeline_layout;
// Correctly update descriptor to avoid "NOT_UPDATED" error
descriptor_set_0.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE); // non-dynamic
descriptor_set_1.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE); // non-dynamic
descriptor_set_2.WriteDescriptorBufferInfo(1, buffer, 0, VK_WHOLE_SIZE); // non-dynamic
// buffer[0, max]
descriptor_set_0.WriteDescriptorBufferInfo(2, buffer, 0, VK_WHOLE_SIZE,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); // pDynamicOffsets[0]
// buffer[alignment, max]
descriptor_set_2.WriteDescriptorBufferInfo(0, buffer, partial_size, VK_WHOLE_SIZE,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); // pDynamicOffsets[1]
// buffer[0, max - alignment]
descriptor_set_2.WriteDescriptorBufferInfo(2, buffer, 0, buffer_size - partial_size, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
0); // pDynamicOffsets[2]s
// buffer[0, max - alignment]
descriptor_set_2.WriteDescriptorBufferInfo(2, buffer, 0, buffer_size - partial_size, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1); // pDynamicOffsets[3]
// buffer[alignment, max - alignment]
descriptor_set_2.WriteDescriptorBufferInfo(3, buffer, partial_size, buffer_size - (partial_size * 2),
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); // pDynamicOffsets[4]
descriptor_set_0.UpdateDescriptorSets();
descriptor_set_1.UpdateDescriptorSets();
descriptor_set_2.UpdateDescriptorSets();
m_command_buffer.Begin();
VkDescriptorSet descriptorSets[3] = {descriptor_set_0.set_, descriptor_set_1.set_, descriptor_set_2.set_};
uint32_t offsets[5] = {0, 0, 0, 0, 0};
if (partial_size > 1) {
// non multiple of alignment
offsets[4] = 1;
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
m_errorMonitor->VerifyFound();
offsets[4] = 0;
}
// Larger than buffer
const uint32_t partial_size32 = static_cast<uint32_t>(partial_size);
offsets[0] = partial_size32;
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-06715");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
m_errorMonitor->VerifyFound();
offsets[0] = 0;
// Larger than buffer
offsets[1] = partial_size32;
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-06715");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
m_errorMonitor->VerifyFound();
offsets[1] = 0;
// Makes the range the same size of buffer which is valid
offsets[2] = partial_size32;
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
// Now an extra increment larger than buffer
offsets[2] = partial_size32 * 2;
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
m_errorMonitor->VerifyFound();
offsets[2] = 0;
// Same thing but with [3] to test descriptor arrays
offsets[3] = partial_size32;
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
offsets[3] = partial_size32 * 2;
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
m_errorMonitor->VerifyFound();
offsets[3] = 0;
// range should be at end of buffer (same size)
offsets[4] = partial_size32;
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
// Now an extra increment larger than buffer
// tests (offset + range + dynamic_offset)
offsets[4] = partial_size32 * 2;
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 3, descriptorSets, 5, offsets);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DynamicOffsetWithNullBuffer) {
TEST_DESCRIPTION("Create a descriptorSet w/ dynamic descriptors where 1 binding is inactive, but all have null buffers");
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device,
{
{2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
VkDescriptorBufferInfo buff_info[3] = {{VK_NULL_HANDLE, 0, 256}, {VK_NULL_HANDLE, 256, 512}, {VK_NULL_HANDLE, 0, 512}};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 3;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
descriptor_write.pBufferInfo = buff_info;
// all 3 descriptors produce this error
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-buffer-02998");
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-buffer-02998");
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-buffer-02998");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
// Create PSO to be used for draw-time errors below
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(set=0) layout(binding=0) uniform foo1 { int x; int y; } bar1;
layout(set=0) layout(binding=2) uniform foo2 { int x; int y; } bar2;
void main(){
x = vec4(bar1.y) + vec4(bar2.y);
}
)glsl";
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&descriptor_set.layout_});
pipe.CreateGraphicsPipeline();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
uint32_t dyn_off[3] = {0, 1024, 256};
// The 2 active descriptors produce this error
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08114");
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08114");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1, &descriptor_set.set_,
3, dyn_off);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DSBufferInfo) {
RETURN_IF_SKIP(Init());
std::vector<VkDescriptorSetLayoutBinding> ds_bindings = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
OneOffDescriptorSet descriptor_set(m_device, ds_bindings);
const VkDeviceSize min_alignment = m_device->Physical().limits_.minUniformBufferOffsetAlignment;
vkt::Buffer buffer(*m_device, min_alignment, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// Cause error due to offset out of range
descriptor_set.WriteDescriptorBufferInfo(0, buffer, min_alignment, VK_WHOLE_SIZE);
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-offset-00340");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
// Now cause error due to range of 0
descriptor_set.Clear();
descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, 0);
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-range-00341");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
// Now cause error due to range exceeding buffer size - offset
descriptor_set.Clear();
descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, min_alignment + 1);
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-range-00342");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSBufferInfoTemplate) {
AddRequiredExtensions(VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
std::vector<VkDescriptorSetLayoutBinding> ds_bindings = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
OneOffDescriptorSet descriptor_set(m_device, ds_bindings);
const VkDeviceSize min_alignment = m_device->Physical().limits_.minUniformBufferOffsetAlignment;
vkt::Buffer buffer(*m_device, min_alignment, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// Setup for update w/ template tests
// Create a template of descriptor set updates
struct SimpleTemplateData {
uint8_t padding[7];
VkDescriptorBufferInfo buffer_info;
uint32_t other_padding[4];
};
SimpleTemplateData update_template_data = {};
update_template_data.buffer_info.buffer = buffer;
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
update_template_entry.offset = offsetof(SimpleTemplateData, buffer_info);
update_template_entry.stride = sizeof(SimpleTemplateData);
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate update_template(*m_device, update_template_ci);
// Cause error due to offset out of range
update_template_data.buffer_info.offset = min_alignment;
update_template_data.buffer_info.range = VK_WHOLE_SIZE;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-offset-00340");
vk::UpdateDescriptorSetWithTemplateKHR(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
// Now cause error due to range of 0
update_template_data.buffer_info.offset = 0;
update_template_data.buffer_info.range = 0;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-range-00341");
vk::UpdateDescriptorSetWithTemplateKHR(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
// Now cause error due to range exceeding buffer size - offset
update_template_data.buffer_info.offset = 0;
update_template_data.buffer_info.range = min_alignment + 1;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-range-00342");
vk::UpdateDescriptorSetWithTemplateKHR(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, ConstantArrayElementNotBound) {
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::Buffer offset_buffer(*m_device, 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
vkt::Buffer write_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, offset_buffer, 0, VK_WHOLE_SIZE);
// Don't bind 2nd element which might be accessed so an error will occur
descriptor_set.WriteDescriptorBufferInfo(1, write_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0);
descriptor_set.UpdateDescriptorSets();
const char vs_source[] = R"glsl(
#version 450
#extension GL_EXT_nonuniform_qualifier : enable
layout(set = 0, binding = 0) uniform ufoo { uint index; };
layout(set = 0, binding = 1) buffer StorageBuffer { uint data; } Data[2];
void main() {
Data[index].data = 0xdeadca71;
}
)glsl";
VkShaderObj vs(*m_device, vs_source, VK_SHADER_STAGE_VERTEX_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[0] = vs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08114");
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8918
TEST_F(NegativeDescriptors, DISABLED_MutableBufferUpdate) {
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
VkDescriptorType desc_types[2] = {
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
};
VkMutableDescriptorTypeListEXT type_list = {2, desc_types};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &type_list;
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}}, 0,
&mdtci);
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
const char *cs_source = R"glsl(
#version 450
layout(set=0, binding=0) buffer SSBO { uint x; };
void main() {
x = 0;
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
NULL);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08114");
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, UpdateDescriptorSetMismatchType) {
RETURN_IF_SKIP(Init());
vkt::Buffer buffer(*m_device, m_device->Physical().limits_.minUniformBufferOffsetAlignment, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr}});
descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
// wrong type
descriptor_set.WriteDescriptorBufferInfo(1, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00319");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorSetCompatibility) {
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorPoolSize ds_type_count[5] = {
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 10}, {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2},
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2}, {VK_DESCRIPTOR_TYPE_SAMPLER, 5},
{VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 2},
};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 5;
ds_pool_ci.poolSizeCount = 5;
ds_pool_ci.pPoolSizes = ds_type_count;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_binding[2] = {};
dsl_binding[0].binding = 0;
dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
dsl_binding[0].descriptorCount = 5;
dsl_binding[0].stageFlags = VK_SHADER_STAGE_ALL;
dsl_binding[0].pImmutableSamplers = NULL;
// Create layout identical to set0 layout but w/ different stageFlags
VkDescriptorSetLayoutBinding dsl_fs_stage_only = {};
dsl_fs_stage_only.binding = 0;
dsl_fs_stage_only.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
dsl_fs_stage_only.descriptorCount = 5;
dsl_fs_stage_only.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; // Different stageFlags to cause error at
// bind time
dsl_fs_stage_only.pImmutableSamplers = NULL;
std::vector<vkt::DescriptorSetLayout> ds_layouts;
// Create 4 unique layouts for full pipelineLayout, and 1 special fs-only
// layout for error case
ds_layouts.emplace_back(*m_device, std::vector<VkDescriptorSetLayoutBinding>(1, dsl_binding[0]));
const vkt::DescriptorSetLayout ds_layout_fs_only(*m_device, {dsl_fs_stage_only});
dsl_binding[0].binding = 0;
dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
dsl_binding[0].descriptorCount = 2;
dsl_binding[1].binding = 1;
dsl_binding[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
dsl_binding[1].descriptorCount = 2;
dsl_binding[1].stageFlags = VK_SHADER_STAGE_ALL;
dsl_binding[1].pImmutableSamplers = NULL;
ds_layouts.emplace_back(*m_device, std::vector<VkDescriptorSetLayoutBinding>({dsl_binding[0], dsl_binding[1]}));
dsl_binding[0].binding = 0;
dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
dsl_binding[0].descriptorCount = 5;
ds_layouts.emplace_back(*m_device, std::vector<VkDescriptorSetLayoutBinding>(1, dsl_binding[0]));
dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
dsl_binding[0].descriptorCount = 2;
ds_layouts.emplace_back(*m_device, std::vector<VkDescriptorSetLayoutBinding>(1, dsl_binding[0]));
std::vector<VkDescriptorSetLayout> ds_vk_layouts;
for (const auto &ds_layout : ds_layouts) {
ds_vk_layouts.push_back(ds_layout);
}
VkDescriptorSet descriptorSet[4] = {};
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorPool = ds_pool;
alloc_info.descriptorSetCount = ds_vk_layouts.size();
alloc_info.pSetLayouts = ds_vk_layouts.data();
VkResult err = vk::AllocateDescriptorSets(device(), &alloc_info, descriptorSet);
ASSERT_EQ(VK_SUCCESS, err);
VkDescriptorSet ds0_fs_only = {};
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &ds_layout_fs_only.handle();
err = vk::AllocateDescriptorSets(device(), &alloc_info, &ds0_fs_only);
ASSERT_EQ(VK_SUCCESS, err);
const vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layouts[0], &ds_layouts[1]});
// Create pipelineLayout with only one setLayout
const vkt::PipelineLayout single_pipe_layout(*m_device, {&ds_layouts[0]});
// Create pipelineLayout with 2 descriptor setLayout at index 0
const vkt::PipelineLayout pipe_layout_one_desc(*m_device, {&ds_layouts[3]});
// Create pipelineLayout with 5 SAMPLER descriptor setLayout at index 0
const vkt::PipelineLayout pipe_layout_five_samp(*m_device, {&ds_layouts[2]});
// Create pipelineLayout with UB type, but stageFlags for FS only
vkt::PipelineLayout pipe_layout_fs_only(*m_device, {&ds_layout_fs_only});
// Create pipelineLayout w/ incompatible set0 layout, but set1 is fine
const vkt::PipelineLayout pipe_layout_bad_set0(*m_device, {&ds_layout_fs_only, &ds_layouts[1]});
// Add buffer binding for UBO
vkt::Buffer buffer(*m_device, 8, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buffer_info{buffer, 0, VK_WHOLE_SIZE};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptorSet[0];
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = &buffer_info;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
// Create PSO to be used for draw-time errors below
VkShaderObj fs(*m_device, kFragmentUniformGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipe_layout_fs_only;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
// TODO : Want to cause various binding incompatibility issues here to test
// DrawState
// First cause various verify_layout_compatibility() fails
// Second disturb early and late sets and verify INFO msgs
// VerifySetLayoutCompatibility fail cases:
// 1. invalid VkPipelineLayout (layout) passed into vk::CmdBindDescriptorSets
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-layout-parameter");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
CastToHandle<VkPipelineLayout, uintptr_t>(0xbaadb1be), 0, 1, &descriptorSet[0], 0, NULL);
m_errorMonitor->VerifyFound();
// 3. Pipeline setLayout[0] has 2 descriptors, but set being bound has 5
// descriptors
m_errorMonitor->SetDesiredError(" has 2 total descriptors, but ");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_one_desc, 0, 1, &descriptorSet[0], 0,
NULL);
m_errorMonitor->VerifyFound();
// 4. same # of descriptors but mismatch in type
m_errorMonitor->SetDesiredError(" is type VK_DESCRIPTOR_TYPE_SAMPLER but binding ");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_five_samp, 0, 1, &descriptorSet[0], 0,
NULL);
m_errorMonitor->VerifyFound();
// 5. same # of descriptors but mismatch in stageFlags
m_errorMonitor->SetDesiredError(" has stageFlags VK_SHADER_STAGE_FRAGMENT_BIT but binding 0 for ");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_fs_only, 0, 1, &descriptorSet[0], 0,
NULL);
m_errorMonitor->VerifyFound();
// Now that we're done actively using the pipelineLayout that gfx pipeline
// was created with, we should be able to delete it. Do that now to verify
// that validation obeys pipelineLayout lifetime
pipe_layout_fs_only.Destroy();
// Cause draw-time errors due to PSO incompatibilities
// 1. Error due to not binding required set (we actually use same code as
// above to disturb set0)
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, &descriptorSet[0], 0, NULL);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_bad_set0, 1, 1, &descriptorSet[1], 0,
NULL);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08600");
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
// 2. Error due to bound set not being compatible with PSO's
// VkPipelineLayout (diff stageFlags in this case)
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, &descriptorSet[0], 0, NULL);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08600");
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
// Remaining clean-up
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DescriptorSetCompatibilityCompute) {
RETURN_IF_SKIP(Init());
vkt::Buffer storage_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkt::Buffer uniform_buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
OneOffDescriptorSet descriptor_set_storage(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
OneOffDescriptorSet descriptor_set_uniform(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
descriptor_set_storage.WriteDescriptorBufferInfo(0, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set_storage.UpdateDescriptorSets();
descriptor_set_uniform.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
descriptor_set_uniform.UpdateDescriptorSets();
const vkt::PipelineLayout pipeline_layout_a(*m_device, {&descriptor_set_storage.layout_, &descriptor_set_storage.layout_});
const vkt::PipelineLayout pipeline_layout_b(*m_device, {&descriptor_set_storage.layout_, &descriptor_set_uniform.layout_});
const char *cs_source = R"glsl(
#version 450
layout(set = 1, binding = 0) buffer StorageBuffer_1 {
uint a;
uint b;
};
void main() {
a = b;
}
)glsl";
CreateComputePipelineHelper pipeline(*this);
pipeline.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT);
pipeline.cp_ci_.layout = pipeline_layout_a;
pipeline.CreateComputePipeline();
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_a, 0, 1,
&descriptor_set_storage.set_, 0, nullptr);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_b, 1, 1,
&descriptor_set_uniform.set_, 0, nullptr);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08600");
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DescriptorSetCompatibilityMutableDescriptors) {
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
VkDescriptorType descriptor_types_0[] = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER};
VkDescriptorType descriptor_types_1[] = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_SAMPLER};
VkMutableDescriptorTypeListEXT type_list = {2, descriptor_types_0};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &type_list;
OneOffDescriptorSet descriptor_set_0(m_device, {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}},
0, &mdtci);
const vkt::PipelineLayout pipeline_layout_0(*m_device, {&descriptor_set_0.layout_});
type_list.pDescriptorTypes = descriptor_types_1;
OneOffDescriptorSet descriptor_set_1(m_device, {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}},
0, &mdtci);
const vkt::PipelineLayout pipeline_layout_1(*m_device, {&descriptor_set_1.layout_});
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
descriptor_set_0.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set_0.UpdateDescriptorSets();
descriptor_set_1.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set_1.UpdateDescriptorSets();
const char *cs_source = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer SSBO {
uint a;
};
void main() {
a = 0;
}
)glsl";
CreateComputePipelineHelper pipeline(*this);
pipeline.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT);
pipeline.cp_ci_.layout = pipeline_layout_0;
pipeline.CreateComputePipeline();
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_1, 0, 1, &descriptor_set_1.set_, 0,
nullptr);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08600");
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DSUsageBits) {
RETURN_IF_SKIP(Init());
const VkFormat buffer_format = VK_FORMAT_R8_UNORM;
if (!BufferFormatAndFeaturesSupported(Gpu(), buffer_format, VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)) {
GTEST_SKIP() << "Format doesn't support storage texel buffer";
}
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
{2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
{3, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{4, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{5, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{6, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{8, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr},
{9, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr},
{10, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::Buffer buffer(*m_device, 256, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT);
vkt::Buffer storage_texel_buffer(*m_device, 256, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
vkt::BufferView buffer_view(*m_device, buffer, VK_FORMAT_R8_UNORM);
vkt::BufferView storage_texel_buffer_view(*m_device, storage_texel_buffer, VK_FORMAT_R8_UNORM);
// Create an image to be used for invalid updates
vkt::Image image(*m_device, 64, 64, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkDescriptorBufferInfo buff_info = {buffer, 0, VK_WHOLE_SIZE};
VkDescriptorImageInfo img_info = {sampler, image_view, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.descriptorCount = 1;
descriptor_write.pBufferInfo = &buff_info;
descriptor_write.pImageInfo = &img_info;
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00337");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00337");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 2;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00339");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 3;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
descriptor_write.pTexelBufferView = &storage_texel_buffer_view.handle();
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-08765");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 5;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
descriptor_write.pTexelBufferView = &buffer_view.handle();
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-08766");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 6;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00330");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 7;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00331");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 8;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00330");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 9;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00331");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 10;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00338");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSUsageBitsFlags2) {
TEST_DESCRIPTION(
"Attempt to update descriptor sets for buffers that do not have correct usage bits sets with VkBufferUsageFlagBits2KHR.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance5);
RETURN_IF_SKIP(Init());
const VkFormat buffer_format = VK_FORMAT_R8_UNORM;
if (!BufferFormatAndFeaturesSupported(Gpu(), buffer_format, VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)) {
GTEST_SKIP() << "Format doesn't support storage texel buffer";
}
VkBufferUsageFlags2CreateInfo buffer_usage_flags = vku::InitStructHelper();
buffer_usage_flags.usage = VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT;
VkBufferCreateInfo buffer_create_info = vku::InitStructHelper(&buffer_usage_flags);
buffer_create_info.size = 1024;
buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
vkt::Buffer buffer(*m_device, buffer_create_info);
vkt::BufferView buffer_view(*m_device, buffer, buffer_format);
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
descriptor_set.WriteDescriptorBufferView(0, buffer_view);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-08766");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSUsageBitsFlags2SubSet) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance5);
RETURN_IF_SKIP(Init());
const VkFormat buffer_format = VK_FORMAT_R8_UNORM;
if (!BufferFormatAndFeaturesSupported(
Gpu(), buffer_format, VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
GTEST_SKIP() << "Format doesn't support storage texel buffer";
}
vkt::Buffer buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
VkBufferUsageFlags2CreateInfo buffer_usage_flags = vku::InitStructHelper();
buffer_usage_flags.usage = VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT;
VkBufferViewCreateInfo bvci = vku::InitStructHelper(&buffer_usage_flags);
bvci.buffer = buffer;
bvci.format = buffer_format;
bvci.range = VK_WHOLE_SIZE;
vkt::BufferView buffer_view(*m_device, bvci);
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
descriptor_set.WriteDescriptorBufferView(0, buffer_view, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-08766");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSBufferLimit) {
TEST_DESCRIPTION(
"Attempt to update buffer descriptor set that has VkDescriptorBufferInfo values that violate device limits.\n"
"Test cases include:\n"
"1. range of uniform buffer update exceeds maxUniformBufferRange\n"
"2. offset of uniform buffer update is not a multiple of minUniformBufferOffsetAlignment\n"
"3. using VK_WHOLE_SIZE with uniform buffer size exceeding maxUniformBufferRange\n"
"4. range of storage buffer update exceeds maxStorageBufferRange\n"
"5. offset of storage buffer update is not a multiple of minStorageBufferOffsetAlignment\n"
"6. using VK_WHOLE_SIZE with storage buffer size exceeding maxStorageBufferRange");
RETURN_IF_SKIP(Init());
struct TestCase {
VkDescriptorType descriptor_type;
VkBufferUsageFlagBits buffer_usage;
VkDeviceSize max_range;
std::string max_range_vu;
VkDeviceSize min_align;
std::string min_align_vu;
};
for (const auto &test_case : {
TestCase({VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
m_device->Physical().limits_.maxUniformBufferRange, "VUID-VkWriteDescriptorSet-descriptorType-00332",
m_device->Physical().limits_.minUniformBufferOffsetAlignment,
"VUID-VkWriteDescriptorSet-descriptorType-00327"}),
TestCase({VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
m_device->Physical().limits_.maxStorageBufferRange, "VUID-VkWriteDescriptorSet-descriptorType-00333",
m_device->Physical().limits_.minStorageBufferOffsetAlignment,
"VUID-VkWriteDescriptorSet-descriptorType-00328"}),
}) {
// Create layout with single buffer
OneOffDescriptorSet descriptor_set(m_device, {
{0, test_case.descriptor_type, 1, VK_SHADER_STAGE_ALL, nullptr},
});
// Create a buffer to be used for invalid updates
VkBufferCreateInfo bci = vku::InitStructHelper();
bci.usage = test_case.buffer_usage;
bci.size = test_case.max_range + test_case.min_align; // Make buffer bigger than range limit
vkt::Buffer buffer(*m_device, bci, vkt::no_mem);
if (buffer == VK_NULL_HANDLE) {
std::string msg = "Failed to allocate buffer of size " + std::to_string(bci.size) + " in DSBufferLimitErrors; skipped";
printf("%s\n", msg.c_str());
continue;
}
// Have to bind memory to buffer before descriptor update
VkMemoryRequirements mem_reqs;
vk::GetBufferMemoryRequirements(device(), buffer, &mem_reqs);
VkMemoryAllocateInfo mem_alloc = vku::InitStructHelper();
mem_alloc.allocationSize = mem_reqs.size;
bool pass = m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &mem_alloc, 0);
if (!pass) {
printf("Failed to allocate memory in DSBufferLimitErrors; skipped.\n");
continue;
}
// This can be triggered due to the extremely large allocation
m_errorMonitor->SetAllowedFailureMsg("UNASSIGNED-vkAllocateMemory-maxMemoryAllocationSize");
vkt::DeviceMemory mem(*m_device, mem_alloc);
if (mem == VK_NULL_HANDLE) {
printf("Failed to allocate memory in DSBufferLimitErrors; skipped.\n");
continue;
}
VkResult err = vk::BindBufferMemory(device(), buffer, mem, 0);
ASSERT_EQ(VK_SUCCESS, err);
VkDescriptorBufferInfo buff_info = {};
buff_info.buffer = buffer;
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.pTexelBufferView = nullptr;
descriptor_write.pBufferInfo = &buff_info;
descriptor_write.pImageInfo = nullptr;
descriptor_write.descriptorType = test_case.descriptor_type;
descriptor_write.dstSet = descriptor_set.set_;
// Exceed range limit
if (test_case.max_range != vvl::kU32Max) {
buff_info.range = test_case.max_range + 1;
buff_info.offset = 0;
m_errorMonitor->SetDesiredError(test_case.max_range_vu.c_str());
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
}
// Reduce size of range to acceptable limit and cause offset error
if (test_case.min_align > 1) {
buff_info.range = test_case.max_range;
buff_info.offset = test_case.min_align - 1;
m_errorMonitor->SetDesiredError(test_case.min_align_vu.c_str());
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
}
// Exceed effective range limit by using VK_WHOLE_SIZE
buff_info.range = VK_WHOLE_SIZE;
buff_info.offset = 0;
m_errorMonitor->SetDesiredError(test_case.max_range_vu.c_str());
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDescriptors, DSTypeMismatch) {
// Create DS w/ layout of one type and attempt Update w/ mis-matched type
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00319");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSUpdateOutOfBounds) {
// For overlapping Update, have arrayIndex exceed that of layout
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// dstArrayElement of 1 is OOB
descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSUpdateOutOfBoundsCombinedSampler) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView image_view = image.CreateView();
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
descriptor_set.WriteDescriptorImageInfo(1, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_IMAGE_LAYOUT_GENERAL, 2);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSUpdateOutOfBoundsCombinedSampler2) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView image_view = image.CreateView();
VkDescriptorImageInfo image_info[3] = {{sampler, image_view, VK_IMAGE_LAYOUT_GENERAL},
{sampler, image_view, VK_IMAGE_LAYOUT_GENERAL},
{sampler, image_view, VK_IMAGE_LAYOUT_GENERAL}};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 1;
descriptor_write.descriptorCount = 3;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.pImageInfo = image_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSUpdateIndex) {
// Create layout w/ count of 1 and attempt update to that layout w/ binding index 2
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstBinding-00315");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
// This is the wrong type, but out of bounds will be flagged first
descriptor_set.WriteDescriptorImageInfo(2, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSUpdateEmptyBinding) {
TEST_DESCRIPTION("Create layout w/ empty binding and attempt to update it");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_SAMPLER, 0 /* !! */, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
// descriptor_write.descriptorCount = 1, Lie here to avoid parameter_validation error
// This is the wrong type, but empty binding error will be flagged first
descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstBinding-00316");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, UpdateIndexSmaller) {
TEST_DESCRIPTION("Only have a binding 2, but try updating binding 1");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{2, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
descriptor_set.WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstBinding-00316");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DSUpdateStruct) {
TEST_DESCRIPTION("Call UpdateDS w/ struct type other than valid VK_STRUCTUR_TYPE_UPDATE_* types");
m_errorMonitor->SetDesiredError(".sType must be VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkDescriptorImageInfo info = {sampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED};
VkWriteDescriptorSet descriptor_write;
memset(&descriptor_write, 0, sizeof(descriptor_write));
descriptor_write.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; /* Intentionally broken struct type */
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.descriptorCount = 1;
// This is the wrong type, but out of bounds will be flagged first
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptor_write.pImageInfo = &info;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, SampleDescriptorUpdate) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
VkSampler sampler = CastToHandle<VkSampler, uintptr_t>(0xbaadbeef); // Sampler with invalid handle
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00325");
descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
descriptor_set.Clear();
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00325");
descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, ImageViewDescriptorUpdate) {
// Create a single combined Image/Sampler descriptor and send it an invalid
// imageView
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02996");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkImageView view = CastToHandle<VkImageView, uintptr_t>(0xbaadbeef); // invalid imageView object
descriptor_set.WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, InputAttachmentDescriptorUpdate) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
VkImageView view = CastToHandle<VkImageView, uintptr_t>(0xbaadbeef); // invalid imageView object
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-07683");
descriptor_set.WriteDescriptorImageInfo(0, view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, InputAttachmentDepthStencilAspect) {
TEST_DESCRIPTION("Checks for InputAttachment image view with more than one aspect.");
RETURN_IF_SKIP(Init());
VkFormat ds_format = FindSupportedDepthStencilFormat(Gpu());
auto image_ci = vkt::Image::ImageCreateInfo2D(128, 128, 1, 1, ds_format, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
vkt::Image image2D(*m_device, image_ci, vkt::set_layout);
vkt::ImageView image_view = image2D.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
descriptor_set.WriteDescriptorImageInfo(0, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
m_errorMonitor->SetDesiredError("VUID-VkDescriptorImageInfo-imageView-01976");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, CopyDescriptorUpdate) {
// Create DS w/ layout of 2 types, write update 1 and attempt to copy-update
// into the other
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstBinding-02632");
RETURN_IF_SKIP(Init());
vkt::Sampler immutable_sampler(*m_device, SafeSaneSamplerCreateInfo());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
OneOffDescriptorSet descriptor_set_2(m_device,
{{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &immutable_sampler.handle()}});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
// SAMPLER binding from layout above
// This write update should succeed
descriptor_set.WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
// Now perform a copy update that fails due to type mismatch
VkCopyDescriptorSet copy_ds_update = vku::InitStructHelper();
copy_ds_update.srcSet = descriptor_set.set_;
copy_ds_update.srcBinding = 1; // Copy from SAMPLER binding
copy_ds_update.dstSet = descriptor_set.set_;
copy_ds_update.dstBinding = 0; // ERROR : copy to UNIFORM binding
copy_ds_update.descriptorCount = 1; // copy 1 descriptor
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
// Now perform a copy update that fails due to binding out of bounds
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcBinding-00345");
copy_ds_update = vku::InitStructHelper();
copy_ds_update.srcSet = descriptor_set.set_;
copy_ds_update.srcBinding = 3; // ERROR : Invalid binding for matching layout
copy_ds_update.dstSet = descriptor_set.set_;
copy_ds_update.dstBinding = 0;
copy_ds_update.descriptorCount = 1; // Copy 1 descriptor
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstBinding-00347");
copy_ds_update = vku::InitStructHelper();
copy_ds_update.srcSet = descriptor_set.set_;
copy_ds_update.srcBinding = 0;
copy_ds_update.dstSet = descriptor_set.set_;
copy_ds_update.dstBinding = 3; // ERROR : Invalid binding for matching layout
copy_ds_update.descriptorCount = 1; // Copy 1 descriptor
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
// Now perform a copy update that fails due to binding out of bounds
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcArrayElement-00346");
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstArrayElement-00348");
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstBinding-02632");
copy_ds_update = vku::InitStructHelper();
copy_ds_update.srcSet = descriptor_set.set_;
copy_ds_update.srcBinding = 1;
copy_ds_update.dstSet = descriptor_set.set_;
copy_ds_update.dstBinding = 0;
copy_ds_update.descriptorCount = 5; // ERROR copy 5 descriptors (out of bounds for layout)
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
// Now perform a copy into an immutable sampler
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstBinding-02753");
copy_ds_update.srcSet = descriptor_set.set_;
copy_ds_update.srcBinding = 1;
copy_ds_update.dstSet = descriptor_set_2.set_;
copy_ds_update.dstBinding = 0;
copy_ds_update.descriptorCount = 1;
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, CopyDescriptorUpdate2) {
RETURN_IF_SKIP(Init());
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}});
OneOffDescriptorSet descriptor_set_2(m_device, {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}});
descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
VkCopyDescriptorSet copy_ds_update = vku::InitStructHelper();
copy_ds_update.srcSet = descriptor_set.set_;
copy_ds_update.dstSet = descriptor_set_2.set_;
copy_ds_update.srcBinding = 0;
copy_ds_update.dstBinding = 0;
copy_ds_update.descriptorCount = 1;
copy_ds_update.srcArrayElement = 1;
copy_ds_update.dstArrayElement = 1;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcArrayElement-00346");
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstArrayElement-00348");
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
copy_ds_update.descriptorCount = 2;
copy_ds_update.srcArrayElement = 0;
copy_ds_update.dstArrayElement = 0;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcArrayElement-00346");
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstArrayElement-00348");
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, Maint1BindingSliceOf3DImage) {
TEST_DESCRIPTION(
"Attempt to bind a slice of a 3D texture in a descriptor set. This is explicitly disallowed by KHR_maintenance1 to keep "
"things simple for drivers.");
AddRequiredExtensions(VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
auto ici = vku::InitStruct<VkImageCreateInfo>(
nullptr, VkImageCreateFlags{VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT}, VK_IMAGE_TYPE_3D, VK_FORMAT_R8G8B8A8_UNORM,
VkExtent3D{32, 32, 32}, 1u, 1u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL,
VkImageUsageFlags{VK_IMAGE_USAGE_SAMPLED_BIT}, VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr, VK_IMAGE_LAYOUT_UNDEFINED);
vkt::Image image(*m_device, ici, vkt::set_layout);
vkt::ImageView view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 0, 1);
m_errorMonitor->SetDesiredError("VUID-VkDescriptorImageInfo-imageView-07796"); // missing VK_EXT_image_2d_view_of_3d
m_errorMonitor->SetDesiredError("VUID-VkDescriptorImageInfo-descriptorType-06714");
descriptor_set.WriteDescriptorImageInfo(0, view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_LAYOUT_GENERAL);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, UpdateDestroyDescriptorSetLayout) {
TEST_DESCRIPTION("Attempt updates to descriptor sets with destroyed descriptor set layouts");
RETURN_IF_SKIP(Init());
// Set up the descriptor (resource) and write/copy operations to use.
vkt::Buffer buffer(*m_device, sizeof(float) * 16, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo info = {};
info.buffer = buffer;
info.range = VK_WHOLE_SIZE;
VkWriteDescriptorSet write_descriptor = vku::InitStructHelper();
write_descriptor.dstSet = VK_NULL_HANDLE; // must update this
write_descriptor.dstBinding = 0;
write_descriptor.descriptorCount = 1;
write_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
write_descriptor.pBufferInfo = &info;
VkCopyDescriptorSet copy_descriptor = vku::InitStructHelper();
copy_descriptor.srcSet = VK_NULL_HANDLE; // must update
copy_descriptor.srcBinding = 0;
copy_descriptor.dstSet = VK_NULL_HANDLE; // must update
copy_descriptor.dstBinding = 0;
copy_descriptor.descriptorCount = 1;
// Create valid and invalid source and destination descriptor sets
std::vector<VkDescriptorSetLayoutBinding> one_uniform_buffer = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
};
OneOffDescriptorSet good_dst(m_device, one_uniform_buffer);
ASSERT_TRUE(good_dst.Initialized());
OneOffDescriptorSet bad_dst(m_device, one_uniform_buffer);
// Must assert before invalidating it below
ASSERT_TRUE(bad_dst.Initialized());
bad_dst.layout_ = vkt::DescriptorSetLayout();
OneOffDescriptorSet good_src(m_device, one_uniform_buffer);
ASSERT_TRUE(good_src.Initialized());
// Put valid data in the good and bad sources, simultaneously doing a positive test on write and copy operations
write_descriptor.dstSet = good_src.set_;
vk::UpdateDescriptorSets(device(), 1, &write_descriptor, 0, NULL);
OneOffDescriptorSet bad_src(m_device, one_uniform_buffer);
ASSERT_TRUE(bad_src.Initialized());
// to complete our positive testing use copy, where above we used write.
copy_descriptor.srcSet = good_src.set_;
copy_descriptor.dstSet = bad_src.set_;
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_descriptor);
bad_src.layout_ = vkt::DescriptorSetLayout();
// Trigger the three invalid use errors
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstSet-00320");
write_descriptor.dstSet = bad_dst.set_;
vk::UpdateDescriptorSets(device(), 1, &write_descriptor, 0, NULL);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstSet-parameter");
copy_descriptor.dstSet = bad_dst.set_;
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_descriptor);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcSet-parameter");
copy_descriptor.srcSet = bad_src.set_;
copy_descriptor.dstSet = good_dst.set_;
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_descriptor);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteDescriptorSetNotAllocated) {
TEST_DESCRIPTION("Try to update a descriptor that has yet to be allocated");
RETURN_IF_SKIP(Init());
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkDescriptorBufferInfo buffer_info = {buffer, 0, sizeof(uint32_t)};
VkDescriptorSet bad_set = CastFromUint64<VkDescriptorSet>(0xcadecade);
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = bad_set;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptor_write.pBufferInfo = &buffer_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstSet-00320");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
VkDescriptorSet null_set = CastFromUint64<VkDescriptorSet>(0);
descriptor_write.dstSet = null_set;
m_errorMonitor->SetDesiredError("UNASSIGNED-GeneralParameterError-RequiredHandle");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, ConsecutiveBindingUpdatesStartOver) {
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr},
{2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buffer_infos[5] = {{buffer, 0, VK_WHOLE_SIZE},
{buffer, 0, VK_WHOLE_SIZE},
{buffer, 0, VK_WHOLE_SIZE},
{buffer, 0, VK_WHOLE_SIZE},
{buffer, 0, VK_WHOLE_SIZE}};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0; // start a 0, but never update one in it
descriptor_write.dstArrayElement = 2;
descriptor_write.descriptorCount = 5; // go over by 1
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = buffer_infos;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstArrayElement = 5; // jump to binding 2
descriptor_write.descriptorCount = 2; // go over by 1
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstArrayElement = 6; // OOB
descriptor_write.descriptorCount = 1;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.dstBinding = 2;
descriptor_write.dstArrayElement = 2; // OOB
descriptor_write.descriptorCount = 1;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, ConsecutiveBindingUpdatesStartOverInConsistent) {
RETURN_IF_SKIP(Init());
// binding 0 is different
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr},
{2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr},
});
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buffer_infos[2] = {{buffer, 0, VK_WHOLE_SIZE}, {buffer, 0, VK_WHOLE_SIZE}};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0; // start a 0, but never update one in it
descriptor_write.dstArrayElement = 2; // try to jump to binding 1, but still different than binding 0
descriptor_write.descriptorCount = 2;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = buffer_infos;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorCount-10776");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, CreateDescriptorPool) {
TEST_DESCRIPTION("Attempt to create descriptor pool with invalid parameters");
RETURN_IF_SKIP(Init());
const uint32_t default_descriptor_count = 1;
const VkDescriptorPoolSize dp_size_template{VK_DESCRIPTOR_TYPE_SAMPLER, default_descriptor_count};
const auto dp_ci_template = vku::InitStruct<VkDescriptorPoolCreateInfo>(nullptr, 0u, 1u, 1u, &dp_size_template);
// try maxSets = 0
{
VkDescriptorPoolCreateInfo invalid_dp_ci = dp_ci_template;
invalid_dp_ci.maxSets = 0; // invalid maxSets value
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolCreateInfo-descriptorPoolOverallocation-09227");
{
VkDescriptorPool pool;
vk::CreateDescriptorPool(device(), &invalid_dp_ci, nullptr, &pool);
}
m_errorMonitor->VerifyFound();
}
// try descriptorCount = 0
{
VkDescriptorPoolSize invalid_dp_size = dp_size_template;
invalid_dp_size.descriptorCount = 0; // invalid descriptorCount value
VkDescriptorPoolCreateInfo dp_ci = dp_ci_template;
dp_ci.pPoolSizes = &invalid_dp_size;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolSize-descriptorCount-00302");
{
VkDescriptorPool pool;
vk::CreateDescriptorPool(device(), &dp_ci, nullptr, &pool);
}
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDescriptors, DuplicateDescriptorBinding) {
TEST_DESCRIPTION("Create a descriptor set layout with a duplicate binding number.");
RETURN_IF_SKIP(Init());
// Create layout where two binding #s are "1"
VkDescriptorSetLayoutBinding dsl_binding[3] = {
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 3;
ds_layout_ci.pBindings = dsl_binding;
VkDescriptorSetLayout ds_layout;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-binding-00279");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, InlineUniformBlockEXT) {
TEST_DESCRIPTION("Test VK_EXT_inline_uniform_block.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::inlineUniformBlock);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceInlineUniformBlockPropertiesEXT inline_uniform_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(inline_uniform_props);
VkDescriptorSetLayoutBinding dslb = {};
std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
// Test too many bindings
dslb_vec.clear();
dslb.binding = 0;
dslb.descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK;
dslb.descriptorCount = 4;
dslb.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
if (inline_uniform_props.maxInlineUniformBlockSize < dslb.descriptorCount) {
GTEST_SKIP() << "DescriptorCount exceeds InlineUniformBlockSize limit";
}
uint32_t maxBlocks = std::max(inline_uniform_props.maxPerStageDescriptorInlineUniformBlocks,
inline_uniform_props.maxDescriptorSetInlineUniformBlocks);
if (maxBlocks > 4096) {
GTEST_SKIP() << "Too large of a maximum number of inline uniform blocks";
}
for (uint32_t i = 0; i < 1 + maxBlocks; ++i) {
dslb.binding = i;
dslb_vec.push_back(dslb);
}
{
ds_layout_ci.bindingCount = dslb_vec.size();
ds_layout_ci.pBindings = dslb_vec.data();
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02214");
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02216");
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02215");
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02217");
VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
pipeline_layout_ci.setLayoutCount = 1;
pipeline_layout_ci.pSetLayouts = &ds_layout.handle();
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
vk::CreatePipelineLayout(device(), &pipeline_layout_ci, NULL, &pipeline_layout);
m_errorMonitor->VerifyFound();
}
{
// Single binding that's too large and is not a multiple of 4
dslb.binding = 0;
dslb.descriptorCount = inline_uniform_props.maxInlineUniformBlockSize + 1;
VkDescriptorSetLayout ds_layout;
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dslb;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-02209");
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-08004");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
}
VkDescriptorPoolInlineUniformBlockCreateInfo pool_inline_info = vku::InitStructHelper();
pool_inline_info.maxInlineUniformBlockBindings = 32;
// Pool size must be a multiple of 4
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 33};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(&pool_inline_info);
ds_pool_ci.flags = 0;
ds_pool_ci.maxSets = 2;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
{
VkDescriptorPool ds_pool = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolSize-type-02218");
vk::CreateDescriptorPool(device(), &ds_pool_ci, NULL, &ds_pool);
m_errorMonitor->VerifyFound();
}
// Create a valid pool
ds_type_count.descriptorCount = 32;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
// Create two valid sets with 8 bytes each
dslb_vec.clear();
dslb.binding = 0;
dslb.descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK;
dslb.descriptorCount = 8;
dslb.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
dslb_vec.push_back(dslb);
dslb.binding = 1;
dslb_vec.push_back(dslb);
ds_layout_ci.bindingCount = dslb_vec.size();
ds_layout_ci.pBindings = &dslb_vec[0];
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorSet descriptor_sets[2];
VkDescriptorSetLayout set_layouts[2] = {ds_layout, ds_layout};
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 2;
alloc_info.descriptorPool = pool;
alloc_info.pSetLayouts = set_layouts;
VkResult err = vk::AllocateDescriptorSets(device(), &alloc_info, descriptor_sets);
ASSERT_EQ(VK_SUCCESS, err);
uint32_t dummyData[8] = {};
VkWriteDescriptorSetInlineUniformBlock write_inline_uniform = vku::InitStructHelper();
write_inline_uniform.dataSize = 3;
write_inline_uniform.pData = &dummyData[0];
// Test invalid VkWriteDescriptorSet parameters (array element and size must be multiple of 4)
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper(&write_inline_uniform);
descriptor_write.dstSet = descriptor_sets[0];
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 3;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK;
// one for dataSiz and for descriptorCount
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02220");
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSetInlineUniformBlock-dataSize-02222");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
descriptor_write.dstArrayElement = 1;
descriptor_write.descriptorCount = 4;
write_inline_uniform.dataSize = 4;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02219");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
descriptor_write.pNext = nullptr;
descriptor_write.dstArrayElement = 0;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02221");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
descriptor_write.pNext = &write_inline_uniform;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL);
// Test invalid VkCopyDescriptorSet parameters (array element and size must be multiple of 4)
VkCopyDescriptorSet copy_ds_update = vku::InitStructHelper();
copy_ds_update.srcSet = descriptor_sets[0];
copy_ds_update.srcBinding = 0;
copy_ds_update.srcArrayElement = 0;
copy_ds_update.dstSet = descriptor_sets[1];
copy_ds_update.dstBinding = 0;
copy_ds_update.dstArrayElement = 0;
copy_ds_update.descriptorCount = 4;
copy_ds_update.srcArrayElement = 1;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcBinding-02223");
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
copy_ds_update.srcArrayElement = 0;
copy_ds_update.dstArrayElement = 1;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstBinding-02224");
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
copy_ds_update.dstArrayElement = 0;
copy_ds_update.descriptorCount = 5;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcBinding-02225");
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
m_errorMonitor->VerifyFound();
copy_ds_update.descriptorCount = 4;
vk::UpdateDescriptorSets(device(), 0, NULL, 1, &copy_ds_update);
}
TEST_F(NegativeDescriptors, InlineUniformBlockEXTFeature) {
TEST_DESCRIPTION("Test VK_EXT_inline_uniform_block features.");
AddRequiredExtensions(VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
// Don't enable any features
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding dslb = {0, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.flags = 0;
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dslb;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-04604");
VkDescriptorSetLayout ds_layout = {};
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, MaxInlineUniformBlockBindings) {
AddRequiredExtensions(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::inlineUniformBlock);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 16};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.flags = 0;
ds_pool_ci.maxSets = 2;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
VkDescriptorPool ds_pool = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolCreateInfo-pPoolSizes-09424");
vk::CreateDescriptorPool(device(), &ds_pool_ci, NULL, &ds_pool);
m_errorMonitor->VerifyFound();
// have struct, but with value of zero
VkDescriptorPoolInlineUniformBlockCreateInfo pool_inline_info = vku::InitStructHelper();
pool_inline_info.maxInlineUniformBlockBindings = 0;
ds_pool_ci.pNext = &pool_inline_info;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolCreateInfo-pPoolSizes-09424");
vk::CreateDescriptorPool(device(), &ds_pool_ci, NULL, &ds_pool);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DstArrayElement) {
RETURN_IF_SKIP(Init());
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
vkt::ImageView view = image.CreateView();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
VkDescriptorImageInfo image_info = {VK_NULL_HANDLE, view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
descriptor_write.pImageInfo = &image_info;
descriptor_write.pBufferInfo = nullptr;
descriptor_write.pTexelBufferView = nullptr;
// sum of 3 pointing into array of 2 bindings
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
descriptor_write.dstArrayElement = 2;
vk::UpdateDescriptorSets(*m_device, 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
OneOffDescriptorSet descriptor_set2(m_device,
{
{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
const VkDescriptorImageInfo image_infos[2] = {image_info, image_info};
descriptor_write.descriptorCount = 2;
descriptor_write.pImageInfo = image_infos;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstArrayElement-00321");
descriptor_write.dstArrayElement = 3;
vk::UpdateDescriptorSets(*m_device, 1, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorSetLayoutMisc) {
TEST_DESCRIPTION("Various invalid ways to create a VkDescriptorSetLayout.");
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding dsl_binding = {1, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dsl_binding;
VkDescriptorSetLayout ds_layout;
// Should succeed with shader stage of 0 or fragment
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
vk::DestroyDescriptorSetLayout(device(), ds_layout, nullptr);
dsl_binding.stageFlags = 0;
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
vk::DestroyDescriptorSetLayout(device(), ds_layout, nullptr);
dsl_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-01510");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorSetLayoutStageFlags) {
TEST_DESCRIPTION("VkDescriptorSetLayout stageFlags are not valid flags");
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding dsl_binding = {1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, 0x3BADFFFF, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dsl_binding;
VkDescriptorSetLayout ds_layout;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorCount-09465");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorSetLayoutImmutableSamplers) {
TEST_DESCRIPTION("VkDescriptorSetLayout with invalid pImmutableSamplers");
RETURN_IF_SKIP(Init());
const VkSampler badhandles[2] = {CastFromUint64<VkSampler>(0xFFFFEEEE), CastFromUint64<VkSampler>(0xDDDDAAAA)};
VkDescriptorSetLayoutBinding dsl_binding = {1, VK_DESCRIPTOR_TYPE_SAMPLER, 2, VK_SHADER_STAGE_FRAGMENT_BIT, badhandles};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dsl_binding;
VkDescriptorSetLayout ds_layout;
// One for each descriptor count
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-00282");
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-00282");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorSetLayoutNullImmutableSamplers) {
TEST_DESCRIPTION("VkDescriptorSetLayout with invalid pImmutableSamplers set to null");
RETURN_IF_SKIP(Init());
const VkSampler null_samples[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE};
VkDescriptorSetLayoutBinding dsl_binding = {1, VK_DESCRIPTOR_TYPE_SAMPLER, 2, VK_SHADER_STAGE_FRAGMENT_BIT, null_samples};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dsl_binding;
VkDescriptorSetLayout ds_layout;
// One for each descriptor count
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-00282");
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-00282");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, NullDescriptorsDisabled) {
RETURN_IF_SKIP(InitFramework());
RETURN_IF_SKIP(InitState());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{2, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02997");
descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
descriptor_set.UpdateDescriptorSets();
descriptor_set.Clear();
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-buffer-02998");
descriptor_set.WriteDescriptorBufferInfo(1, VK_NULL_HANDLE, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
descriptor_set.Clear();
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02995");
VkBufferView buffer_view = VK_NULL_HANDLE;
descriptor_set.WriteDescriptorBufferView(2, buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
descriptor_set.UpdateDescriptorSets();
descriptor_set.Clear();
m_errorMonitor->VerifyFound();
m_command_buffer.Begin();
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceSize offset = 0;
m_errorMonitor->SetDesiredError("VUID-vkCmdBindVertexBuffers-pBuffers-04001");
vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &buffer, &offset);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, NullDescriptorsEnabled) {
AddRequiredExtensions(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::nullDescriptor);
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{2, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
descriptor_set.WriteDescriptorBufferInfo(1, VK_NULL_HANDLE, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
VkBufferView buffer_view = VK_NULL_HANDLE;
descriptor_set.WriteDescriptorBufferView(2, buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
descriptor_set.UpdateDescriptorSets();
descriptor_set.Clear();
m_command_buffer.Begin();
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceSize offset = 0;
vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &buffer, &offset);
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-buffer-02999");
descriptor_set.WriteDescriptorBufferInfo(1, VK_NULL_HANDLE, 0, 16, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
offset = 1;
m_errorMonitor->SetDesiredError("VUID-vkCmdBindVertexBuffers-pBuffers-04002");
vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &buffer, &offset);
m_command_buffer.End();
m_errorMonitor->VerifyFound();
// Make sure sampler with NULL image view doesn't cause a crash or errors
OneOffDescriptorSet sampler_descriptor_set(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}});
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
sampler_descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
sampler_descriptor_set.UpdateDescriptorSets();
const vkt::PipelineLayout pipeline_layout(*m_device, {&sampler_descriptor_set.layout_});
const char *fsSource = R"glsl(
#version 450
layout(set=0, binding=0) uniform sampler2D tex;
layout(location=0) out vec4 x;
void main(){
x = texture(tex, vec2(1));
}
)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();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1,
&sampler_descriptor_set.set_, 0, nullptr);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8095
TEST_F(NegativeDescriptors, DISABLED_ImageSubresourceOverlapBetweenAttachmentsAndDescriptorSets) {
TEST_DESCRIPTION("Validate if attachments and descriptor set use the same image subresources");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const VkFormat depth_format = FindSupportedDepthOnlyFormat(Gpu());
vkt::Image depth_image(
*m_device, 64, 64, depth_format,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView depth_view = depth_image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT);
VkImageUsageFlags usage = VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
auto image_ci = vkt::Image::ImageCreateInfo2D(64, 64, 1, 2, format, usage);
vkt::Image image(*m_device, image_ci, vkt::set_layout);
vkt::ImageView view_input = image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 1, 1);
VkImageView attachments[] = {view_input, depth_view};
vkt::ImageView view_sampler_overlap = image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 1, 1);
vkt::ImageView view_sampler_not_overlap = image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 0, 1);
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(format, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
rp.AddAttachmentDescription(depth_format);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_GENERAL});
rp.AddInputAttachment(0);
rp.AddDepthStencilAttachment(1);
rp.CreateRenderPass();
vkt::Framebuffer fb(*m_device, rp, 2u, attachments, 64, 64);
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
const char *fsSource = R"glsl(
#version 450
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput ia0;
layout(set=0, binding=1) uniform sampler2D ci1;
layout(set=0, binding=2) uniform sampler2D ci2;
layout(set=0, binding=3) uniform sampler2D ci3;
layout(set=0, binding=4) uniform sampler2D ci4;
void main() {
vec4 color = subpassLoad(ia0);
color = texture(ci1, vec2(0));
color = texture(ci2, vec2(0));
color = texture(ci3, vec2(0));
color = texture(ci4, vec2(0));
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper g_pipe(*this);
g_pipe.shader_stages_ = {g_pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
g_pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}};
VkPipelineDepthStencilStateCreateInfo pipe_ds_state_ci = vku::InitStructHelper();
pipe_ds_state_ci.depthTestEnable = VK_TRUE;
pipe_ds_state_ci.stencilTestEnable = VK_FALSE;
g_pipe.gp_ci_.pDepthStencilState = &pipe_ds_state_ci;
g_pipe.gp_ci_.renderPass = rp;
g_pipe.CreateGraphicsPipeline();
g_pipe.descriptor_set_->WriteDescriptorImageInfo(0, view_input, sampler, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
// input attachment and combined image sampler use the same view to cause DesiredFailure.
g_pipe.descriptor_set_->WriteDescriptorImageInfo(1, view_input, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
// image subresource of input attachment and combined image sampler overlap to cause DesiredFailure.
g_pipe.descriptor_set_->WriteDescriptorImageInfo(2, view_sampler_overlap, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
// image subresource of input attachment and combined image sampler don't overlap. It should not cause failure.
g_pipe.descriptor_set_->WriteDescriptorImageInfo(3, view_sampler_not_overlap, sampler,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
// Both image subresource and depth stencil attachment are read only. It should not cause failure.
g_pipe.descriptor_set_->WriteDescriptorImageInfo(4, depth_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_IMAGE_LAYOUT_GENERAL);
g_pipe.descriptor_set_->UpdateDescriptorSets();
m_command_buffer.Begin();
m_renderPassBeginInfo.renderArea = {{0, 0}, {64, 64}};
m_renderPassBeginInfo.renderPass = rp;
m_renderPassBeginInfo.framebuffer = fb;
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_, 0, 1,
&g_pipe.descriptor_set_->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09002");
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, CreateDescriptorPoolFlags) {
TEST_DESCRIPTION("Create descriptor pool with invalid flags.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_SAMPLER, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT | VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
VkDescriptorPool bad_pool;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolCreateInfo-flags-04607");
vk::CreateDescriptorPool(device(), &ds_pool_ci, NULL, &bad_pool);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, MissingMutableDescriptorTypeFeature) {
TEST_DESCRIPTION("Create mutable descriptor pool with feature not enabled.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_SAMPLER, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT;
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
VkDescriptorPool bad_pool;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolCreateInfo-flags-04609");
vk::CreateDescriptorPool(device(), &ds_pool_ci, NULL, &bad_pool);
m_errorMonitor->VerifyFound();
ds_type_count.type = VK_DESCRIPTOR_TYPE_MUTABLE_EXT;
ds_pool_ci.flags = 0;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolCreateInfo-mutableDescriptorType-04608");
vk::CreateDescriptorPool(device(), &ds_pool_ci, NULL, &bad_pool);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, MutableDescriptorPoolsWithPartialOverlap) {
TEST_DESCRIPTION("Create mutable descriptor pools with partial overlap.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize pool_sizes[2] = {
{VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1},
{VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1},
};
VkDescriptorType first_types[2] = {
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
};
VkDescriptorType second_types[2] = {
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
};
VkMutableDescriptorTypeListEXT lists[2] = {{2, first_types}, {2, second_types}};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 2;
mdtci.pMutableDescriptorTypeLists = lists;
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(&mdtci);
ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT;
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 2;
ds_pool_ci.pPoolSizes = pool_sizes;
{
VkDescriptorPool pool;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolCreateInfo-pPoolSizes-04787");
vk::CreateDescriptorPool(device(), &ds_pool_ci, nullptr, &pool);
m_errorMonitor->VerifyFound();
lists[1].pDescriptorTypes = first_types;
mdtci.mutableDescriptorTypeListCount = 1;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorPoolCreateInfo-pPoolSizes-04787");
vk::CreateDescriptorPool(device(), &ds_pool_ci, nullptr, &pool);
m_errorMonitor->VerifyFound();
}
{
mdtci.mutableDescriptorTypeListCount = 2;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
}
{
second_types[0] = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
lists[1].pDescriptorTypes = second_types;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
}
}
TEST_F(NegativeDescriptors, CreateDescriptorPoolAllocateFlags) {
TEST_DESCRIPTION("Create descriptor pool with invalid flags.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_SAMPLER, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.flags = 0;
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_binding_samp = {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr};
const vkt::DescriptorSetLayout ds_layout_samp(*m_device, {dsl_binding_samp},
VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT);
VkDescriptorSetLayout set_layout = ds_layout_samp;
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 1;
alloc_info.descriptorPool = pool;
alloc_info.pSetLayouts = &set_layout;
VkDescriptorSet descriptor_set;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetAllocateInfo-pSetLayouts-04610");
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_set);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorUpdateOfMultipleBindingWithOneUpdateCall) {
TEST_DESCRIPTION("Update a descriptor set containing multiple bindings with only one update");
AddRequiredExtensions(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::inlineUniformBlock);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceInlineUniformBlockPropertiesEXT inlineUniformProps = vku::InitStructHelper();
GetPhysicalDeviceProperties2(inlineUniformProps);
VkResult res;
float inline_data[] = {1.f, 2.f};
vkt::DescriptorSetLayout descLayout;
{
VkDescriptorSetLayoutBinding layoutBinding[3] = {};
uint32_t bindingCount[] = {sizeof(inline_data) / 2, 0, sizeof(inline_data) / 2};
uint32_t bindingPoint[] = {0, 1, 2};
VkDescriptorType descType[] = {VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK};
for (size_t i = 0; i < 3; ++i) {
layoutBinding[i].binding = bindingPoint[i];
layoutBinding[i].descriptorCount = bindingCount[i];
layoutBinding[i].descriptorType = descType[i];
layoutBinding[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
}
VkDescriptorSetLayoutCreateInfo layoutCreate = vku::InitStructHelper();
layoutCreate.bindingCount = 3;
layoutCreate.pBindings = layoutBinding;
if (inlineUniformProps.maxInlineUniformBlockSize < bindingCount[0] ||
inlineUniformProps.maxInlineUniformBlockSize < bindingCount[1]) {
GTEST_SKIP() << "DescriptorCount exceeds InlineUniformBlockSize limit";
}
descLayout.Init(*m_device, layoutCreate);
ASSERT_TRUE(descLayout.initialized());
}
vkt::DescriptorPool descPool;
{
VkDescriptorPoolInlineUniformBlockCreateInfo descPoolInlineInfo = vku::InitStructHelper();
descPoolInlineInfo.maxInlineUniformBlockBindings = 2;
VkDescriptorPoolSize poolSize[2] = {{VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, sizeof(inline_data)},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1}};
VkDescriptorPoolCreateInfo poolCreate = vku::InitStructHelper(&descPoolInlineInfo);
poolCreate.poolSizeCount = 2;
poolCreate.pPoolSizes = poolSize;
poolCreate.maxSets = 1;
descPool.Init(*m_device, poolCreate);
ASSERT_TRUE(descPool.initialized());
}
VkDescriptorSet descSetHandle = VK_NULL_HANDLE;
{
VkDescriptorSetAllocateInfo allocInfo = vku::InitStructHelper();
allocInfo.pSetLayouts = &descLayout.handle();
allocInfo.descriptorSetCount = 1;
allocInfo.descriptorPool = descPool;
// The Galaxy S10 device used in LunarG CI fails to allocate this descriptor set
res = vk::AllocateDescriptorSets(device(), &allocInfo, &descSetHandle);
if (res != VK_SUCCESS) {
GTEST_SKIP() << "vkAllocateDescriptorSets failed with error";
}
}
vkt::DescriptorSet descSet(*m_device, &descPool, descSetHandle);
VkWriteDescriptorSetInlineUniformBlock writeInlineUbDesc = vku::InitStructHelper();
writeInlineUbDesc.dataSize = sizeof(inline_data);
writeInlineUbDesc.pData = inline_data;
VkWriteDescriptorSet writeDesc = vku::InitStructHelper(&writeInlineUbDesc);
writeDesc.descriptorCount = sizeof(inline_data);
writeDesc.descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK;
writeDesc.dstBinding = 0;
writeDesc.dstArrayElement = 0;
writeDesc.dstSet = descSet;
m_errorMonitor->Reset();
vk::UpdateDescriptorSets(device(), 1, &writeDesc, 0, nullptr);
}
TEST_F(NegativeDescriptors, WriteMutableDescriptorSet) {
TEST_DESCRIPTION("Write mutable descriptor set with invalid type.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_binding = {0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorType types[2] = {
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
};
VkMutableDescriptorTypeListEXT list = {2, types};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &list;
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&mdtci);
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dsl_binding;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorSetLayout ds_layout_handle = ds_layout;
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 1;
allocate_info.pSetLayouts = &ds_layout_handle;
VkDescriptorSet descriptor_set;
VkResult err = vk::AllocateDescriptorSets(device(), &allocate_info, &descriptor_set);
ASSERT_EQ(VK_SUCCESS, err);
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
VkDescriptorBufferInfo buffer_info = {buffer, 0, VK_WHOLE_SIZE};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = &buffer_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstSet-04611");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
}
TEST_F(NegativeDescriptors, WriteMutableDescriptorSet2) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10785");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 2};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_bindings[2]{{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr},
{2, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr}};
VkDescriptorType types_0[1] = {VK_DESCRIPTOR_TYPE_SAMPLER};
VkDescriptorType types_2[2] = {
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
};
VkMutableDescriptorTypeListEXT type_list[2] = {
{1, types_0},
{2, types_2},
};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 2;
mdtci.pMutableDescriptorTypeLists = type_list;
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&mdtci);
ds_layout_ci.bindingCount = 2;
ds_layout_ci.pBindings = dsl_bindings;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorSetLayout ds_layout_handle = ds_layout;
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 1;
allocate_info.pSetLayouts = &ds_layout_handle;
VkDescriptorSet descriptor_set;
VkResult err = vk::AllocateDescriptorSets(device(), &allocate_info, &descriptor_set);
ASSERT_EQ(VK_SUCCESS, err);
vkt::Image image(*m_device, 16, 16, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkt::ImageView image_view = image.CreateView();
VkDescriptorImageInfo image_info = {VK_NULL_HANDLE, image_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set;
descriptor_write.dstBinding = 2;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
descriptor_write.pImageInfo = &image_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstSet-04611");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, WriteMutableDescriptorSet3) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10785");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 2};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_bindings[2]{{1, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr},
{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr}};
// map to binding 1
VkDescriptorType types_0[2] = {
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
};
// map to binding 0
VkDescriptorType types_1[1] = {VK_DESCRIPTOR_TYPE_SAMPLER};
VkMutableDescriptorTypeListEXT type_list[2] = {
{2, types_0},
{1, types_1},
};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 2;
mdtci.pMutableDescriptorTypeLists = type_list;
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&mdtci);
ds_layout_ci.bindingCount = 2;
ds_layout_ci.pBindings = dsl_bindings;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorSetLayout ds_layout_handle = ds_layout;
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 1;
allocate_info.pSetLayouts = &ds_layout_handle;
VkDescriptorSet descriptor_set;
VkResult err = vk::AllocateDescriptorSets(device(), &allocate_info, &descriptor_set);
ASSERT_EQ(VK_SUCCESS, err);
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkDescriptorImageInfo image_info = {sampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set;
descriptor_write.dstBinding = 1;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptor_write.pImageInfo = &image_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstSet-04611");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, MutableDescriptors) {
TEST_DESCRIPTION("Test mutable descriptors");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding dsl_binding = {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorType descriptor_types[] = {VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLER};
VkMutableDescriptorTypeListEXT mutable_descriptor_type_list = {1, descriptor_types};
VkMutableDescriptorTypeCreateInfoEXT mutable_descriptor_type_ci = vku::InitStructHelper();
mutable_descriptor_type_ci.mutableDescriptorTypeListCount = 1;
mutable_descriptor_type_ci.pMutableDescriptorTypeLists = &mutable_descriptor_type_list;
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&mutable_descriptor_type_ci);
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dsl_binding;
VkDescriptorSetLayout ds_layout;
m_errorMonitor->SetDesiredError("VUID-VkMutableDescriptorTypeListEXT-descriptorTypeCount-04599");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
mutable_descriptor_type_list.descriptorTypeCount = 0;
dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_MUTABLE_EXT;
m_errorMonitor->SetDesiredError("VUID-VkMutableDescriptorTypeListEXT-descriptorTypeCount-04597");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
mutable_descriptor_type_list.descriptorTypeCount = 2;
m_errorMonitor->SetDesiredError("VUID-VkMutableDescriptorTypeListEXT-pDescriptorTypes-04598");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
descriptor_types[1] = VK_DESCRIPTOR_TYPE_MUTABLE_EXT;
m_errorMonitor->SetDesiredError("VUID-VkMutableDescriptorTypeListEXT-pDescriptorTypes-04600");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
descriptor_types[1] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
m_errorMonitor->SetDesiredError("VUID-VkMutableDescriptorTypeListEXT-pDescriptorTypes-04601");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
descriptor_types[1] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
m_errorMonitor->SetDesiredError("VUID-VkMutableDescriptorTypeListEXT-pDescriptorTypes-04602");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
descriptor_types[1] = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK;
m_errorMonitor->SetDesiredError("VUID-VkMutableDescriptorTypeListEXT-pDescriptorTypes-04603");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorUpdateTemplate) {
TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV than allowed");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_binding = {0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorType types[2] = {
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
};
VkMutableDescriptorTypeListEXT list = {2, types};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &list;
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&mdtci);
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &dsl_binding;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorSetLayout ds_layout_handle = ds_layout;
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
update_template_entry.offset = 0;
update_template_entry.stride = 16;
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = ds_layout_handle;
VkDescriptorUpdateTemplate update_template = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-04615");
vk::CreateDescriptorUpdateTemplate(device(), &update_template_ci, nullptr, &update_template);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, MutableDescriptorSetLayout) {
TEST_DESCRIPTION("Create mutable descriptor set layout.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &binding;
VkDescriptorSetLayout ds_layout;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-pBindings-07303");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, nullptr, &ds_layout);
m_errorMonitor->VerifyFound();
VkDescriptorType types[2] = {
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
};
VkMutableDescriptorTypeListEXT list = {2, types};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &list;
ds_layout_ci.pNext = &mdtci;
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
binding.pImmutableSamplers = &sampler.handle();
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-04594");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, nullptr, &ds_layout);
m_errorMonitor->VerifyFound();
binding.pImmutableSamplers = nullptr;
sampler.Destroy();
}
TEST_F(NegativeDescriptors, MutableDescriptorSetLayoutMissingFeature) {
TEST_DESCRIPTION("Create mutable descriptor set layout without mutableDescriptorType feature enabled.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT; // Invalid, feature is not enabled
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &binding;
VkDescriptorSetLayout ds_layout;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-flags-04596");
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, nullptr, &ds_layout);
m_errorMonitor->VerifyFound();
VkDescriptorType types[2] = {
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
};
VkMutableDescriptorTypeListEXT list = {2, types};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &list;
ds_layout_ci.pNext = &mdtci;
ds_layout_ci.flags = 0;
binding.descriptorType = VK_DESCRIPTOR_TYPE_MUTABLE_EXT;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-mutableDescriptorType-04595");
m_errorMonitor->SetUnexpectedError(
"VUID-VkDescriptorSetLayoutCreateInfo-pNext-pNext"); // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2457
vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, nullptr, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, ImageSubresourceOverlapBetweenRenderPassAndDescriptorSets) {
TEST_DESCRIPTION("Validate if attachments in render pass and descriptor set use the same image subresources");
AddRequiredFeature(vkt::Feature::shaderStorageImageWriteWithoutFormat);
AddRequiredFeature(vkt::Feature::fragmentStoresAndAtomics);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(format, VK_IMAGE_LAYOUT_UNDEFINED);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddColorAttachment(0);
rp.CreateRenderPass();
auto image_create_info =
vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
vkt::Image image(*m_device, image_create_info, vkt::set_layout);
vkt::ImageView image_view = image.CreateView();
VkImageView image_view_handle = image_view;
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Framebuffer framebuffer(*m_device, rp, 1, &image_view_handle);
const char *fsSource = R"glsl(
#version 450
layout(location = 0) out vec4 x;
layout(set = 0, binding = 0) writeonly uniform image2D image;
void main(){
x = vec4(1.0f);
imageStore(image, ivec2(0), vec4(0.5f));
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.gp_ci_.renderPass = rp;
pipe.CreateGraphicsPipeline();
descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-06537");
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, framebuffer, 32, 32, 1, m_renderPassClearValues.data());
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, ImageSubresourceOverlapBetweenRenderPassAndDescriptorSetsFunction) {
TEST_DESCRIPTION("Validate if attachments in render pass and descriptor set use the same image subresources");
AddRequiredFeature(vkt::Feature::fragmentStoresAndAtomics);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(format, VK_IMAGE_LAYOUT_UNDEFINED);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddColorAttachment(0);
rp.CreateRenderPass();
auto image_create_info =
vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
vkt::Image image(*m_device, image_create_info, vkt::set_layout);
vkt::ImageView image_view = image.CreateView();
VkImageView image_view_handle = image_view;
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Framebuffer framebuffer(*m_device, rp, 1, &image_view_handle);
// used as a "would be valid" image
vkt::Image image_2(*m_device, image_create_info, vkt::set_layout);
vkt::ImageView image_view_2 = image_2.CreateView();
// like the following, but does OpLoad before function call
// layout(location = 0) out vec4 x;
// layout(set = 0, binding = 0, rgba8) uniform image2D image_0;
// layout(set = 0, binding = 1, rgba8) uniform image2D image_1;
// void foo(image2D bar) {
// imageStore(bar, ivec2(0), vec4(0.5f));
// }
// void main() {
// x = vec4(1.0f);
// foo(image_0);
// }
const char *fsSource = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %color_attach
OpExecutionMode %main OriginUpperLeft
OpDecorate %color_attach Location 0
OpDecorate %image_0 DescriptorSet 0
OpDecorate %image_0 Binding 0
OpDecorate %image_1 DescriptorSet 0
OpDecorate %image_1 Binding 1
%void = OpTypeVoid
%6 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%color_attach = OpVariable %_ptr_Output_v4float Output
%float_1 = OpConstant %float 1
%11 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
%12 = OpTypeImage %float 2D 0 0 0 2 Rgba8
%13 = OpTypeFunction %void %12
%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
%image_0 = OpVariable %_ptr_UniformConstant_12 UniformConstant
%int = OpTypeInt 32 1
%v2int = OpTypeVector %int 2
%int_0 = OpConstant %int 0
%18 = OpConstantComposite %v2int %int_0 %int_0
%float_0_5 = OpConstant %float 0.5
%20 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
%image_1 = OpVariable %_ptr_UniformConstant_12 UniformConstant
%foo = OpFunction %void None %13
%bar = OpFunctionParameter %12
%23 = OpLabel
OpImageWrite %bar %18 %20
OpReturn
OpFunctionEnd
%main = OpFunction %void None %6
%24 = OpLabel
OpStore %color_attach %11
%25 = OpLoad %12 %image_0
%26 = OpFunctionCall %void %foo %25
OpReturn
OpFunctionEnd
)";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.gp_ci_.renderPass = rp;
pipe.CreateGraphicsPipeline();
descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL);
descriptor_set.WriteDescriptorImageInfo(1, image_view_2, sampler, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-06537");
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, framebuffer, 32, 32, 1, m_renderPassClearValues.data());
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->VerifyFound();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8095
TEST_F(NegativeDescriptors, DISABLED_DescriptorReadFromWriteAttachment) {
TEST_DESCRIPTION("Validate reading from a descriptor that uses same image view as framebuffer write attachment");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const uint32_t width = 32;
const uint32_t height = 32;
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(format, VK_IMAGE_LAYOUT_UNDEFINED);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddColorAttachment(0);
rp.CreateRenderPass();
auto image_create_info =
vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
vkt::Image image(*m_device, image_create_info, vkt::set_layout);
vkt::ImageView image_view = image.CreateView();
VkImageView image_view_handle = image_view;
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Framebuffer framebuffer(*m_device, rp, 1, &image_view_handle, width, height);
const char *fsSource = R"glsl(
#version 450
layout(location = 0) out vec4 color;
layout(set = 0, binding = 0, rgba8) readonly uniform image2D image1;
void main(){
color = imageLoad(image1, ivec2(0));
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const vkt::DescriptorSetLayout descriptor_set_layout(
*m_device, {0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_layout, &descriptor_set_layout});
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.gp_ci_.renderPass = rp;
pipe.CreateGraphicsPipeline();
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
VkDescriptorImageInfo image_info = {sampler, image_view, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
descriptor_write.pImageInfo = &image_info;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09000");
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, framebuffer, width, height, 1, m_renderPassClearValues.data());
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorWriteFromReadAttachment) {
TEST_DESCRIPTION("Validate writting to a descriptor that uses same image view as framebuffer read attachment");
AddRequiredFeature(vkt::Feature::fragmentStoresAndAtomics);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const uint32_t width = 32;
const uint32_t height = 32;
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(format, VK_IMAGE_LAYOUT_UNDEFINED);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddInputAttachment(0);
rp.CreateRenderPass();
auto image_create_info =
vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, format, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
vkt::Image image(*m_device, image_create_info, vkt::set_layout);
vkt::ImageView image_view = image.CreateView();
VkImageView image_view_handle = image_view;
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Framebuffer framebuffer(*m_device, rp, 1, &image_view_handle, width, height);
const char *fsSource = R"glsl(
#version 450
layout(set = 0, binding = 0, rgba8) writeonly uniform image2D image1;
layout(set = 1, binding = 0, input_attachment_index = 0) uniform subpassInput inputColor;
void main(){
vec4 color = subpassLoad(inputColor);
imageStore(image1, ivec2(0), color);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const vkt::DescriptorSetLayout descriptor_set_layout1(
*m_device, {0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr});
const vkt::DescriptorSetLayout descriptor_set_layout2(
*m_device, {0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_layout1, &descriptor_set_layout2});
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.gp_ci_.renderPass = rp;
pipe.CreateGraphicsPipeline();
OneOffDescriptorSet descriptor_set_storage_image(
m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
OneOffDescriptorSet descriptor_set_input_attachment(
m_device, {
{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
descriptor_set_storage_image.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
VK_IMAGE_LAYOUT_GENERAL);
descriptor_set_storage_image.UpdateDescriptorSets();
descriptor_set_input_attachment.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
VK_IMAGE_LAYOUT_GENERAL);
descriptor_set_input_attachment.UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, framebuffer, width, height, 1, m_renderPassClearValues.data());
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1,
&descriptor_set_storage_image.set_, 0, nullptr);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 1, 1,
&descriptor_set_input_attachment.set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-06537"); // write
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-06539"); // read
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
// https://gitlab.khronos.org/vulkan/vulkan/-/issues/3297
// This should be checked earlier as causes some driver to crash
TEST_F(NegativeDescriptors, DISABLED_AllocatingVariableDescriptorSets) {
TEST_DESCRIPTION("Test allocating large variable descriptor sets");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount);
RETURN_IF_SKIP(Init());
VkDescriptorBindingFlags flags[2] = {0, VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT};
VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = 2;
flags_create_info.pBindingFlags = flags;
VkDescriptorSetLayoutBinding bindings[2] = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 10, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vvl::kU32Max / 64, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&flags_create_info);
ds_layout_ci.bindingCount = 2;
ds_layout_ci.pBindings = bindings;
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorSetLayout ds_layout_handle = ds_layout;
VkDescriptorSetVariableDescriptorCountAllocateInfo count_alloc_info = vku::InitStructHelper();
count_alloc_info.descriptorSetCount = 1;
uint32_t variable_count = 2;
count_alloc_info.pDescriptorCounts = &variable_count;
VkDescriptorPoolSize pool_sizes[2] = {{bindings[0].descriptorType, bindings[0].descriptorCount},
{bindings[1].descriptorType, bindings[1].descriptorCount}};
VkDescriptorPoolCreateInfo dspci = vku::InitStructHelper();
dspci.poolSizeCount = 2;
dspci.pPoolSizes = pool_sizes;
dspci.maxSets = 1;
vkt::DescriptorPool pool(*m_device, dspci);
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);
}
TEST_F(NegativeDescriptors, DescriptorSetLayoutBinding) {
TEST_DESCRIPTION("Create invalid descriptor set layout.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, &sampler.handle()};
VkDescriptorType descriptor_types[] = {VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLER};
VkMutableDescriptorTypeListEXT mutable_descriptor_type_list = {1, descriptor_types};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &mutable_descriptor_type_list;
VkDescriptorSetLayoutCreateInfo create_info = vku::InitStructHelper(&mdtci);
create_info.bindingCount = 1;
create_info.pBindings = &binding;
VkDescriptorSetLayout dsl;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-04605");
// need to skip to allow hitting the above error
m_errorMonitor->SetAllowedFailureMsg("VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-04594");
vk::CreateDescriptorSetLayout(*m_device, &create_info, nullptr, &dsl);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, BindingDescriptorSetFromHostOnlyPool) {
TEST_DESCRIPTION(
"Try to bind a descriptor set that was allocated from a pool with VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT;
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
const vkt::DescriptorSetLayout ds_layout(*m_device, {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr});
VkDescriptorSetLayout ds_layout_handle = ds_layout;
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 1;
allocate_info.pSetLayouts = &ds_layout_handle;
VkDescriptorSet descriptor_set;
vk::AllocateDescriptorSets(device(), &allocate_info, &descriptor_set);
vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout});
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-04616");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set, 0,
nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, CopyMutableDescriptors) {
TEST_DESCRIPTION("Copy mutable descriptors.");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
{
VkDescriptorType descriptor_types[] = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER};
VkMutableDescriptorTypeListEXT mutable_descriptor_type_list = {1, descriptor_types};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &mutable_descriptor_type_list;
VkDescriptorPoolSize pool_sizes[2] = {{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2}, {VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 2}};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(&mdtci);
ds_pool_ci.maxSets = 2;
ds_pool_ci.poolSizeCount = 2;
ds_pool_ci.pPoolSizes = pool_sizes;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding bindings[2] = {
{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}};
VkDescriptorSetLayoutCreateInfo create_info = vku::InitStructHelper(&mdtci);
create_info.bindingCount = 2;
create_info.pBindings = bindings;
vkt::DescriptorSetLayout set_layout(*m_device, create_info);
VkDescriptorSetLayout set_layout_handle = set_layout;
VkDescriptorSetLayout layouts[2] = {set_layout_handle, set_layout_handle};
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 2;
allocate_info.pSetLayouts = layouts;
VkDescriptorSet descriptor_sets[2];
vk::AllocateDescriptorSets(device(), &allocate_info, descriptor_sets);
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
VkDescriptorBufferInfo buffer_info = {buffer, 0, VK_WHOLE_SIZE};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_sets[0];
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = &buffer_info;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
VkCopyDescriptorSet copy_set = vku::InitStructHelper();
copy_set.srcSet = descriptor_sets[1];
copy_set.srcBinding = 1;
copy_set.dstSet = descriptor_sets[0];
copy_set.dstBinding = 0;
copy_set.descriptorCount = 1;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstSet-04612");
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_set);
m_errorMonitor->VerifyFound();
}
{
VkDescriptorType descriptor_types[] = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE};
VkMutableDescriptorTypeListEXT mutable_descriptor_type_lists[2] = {{1, &descriptor_types[0]}, {1, &descriptor_types[1]}};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 2;
mdtci.pMutableDescriptorTypeLists = mutable_descriptor_type_lists;
VkDescriptorPoolSize pool_sizes[2] = {{VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 4}, {VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 4}};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(&mdtci);
ds_pool_ci.maxSets = 2;
ds_pool_ci.poolSizeCount = 2;
ds_pool_ci.pPoolSizes = pool_sizes;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding bindings[2] = {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_ALL, nullptr}};
VkDescriptorSetLayoutCreateInfo create_info = vku::InitStructHelper(&mdtci);
create_info.bindingCount = 2;
create_info.pBindings = bindings;
vkt::DescriptorSetLayout set_layout(*m_device, create_info);
VkDescriptorSetLayout set_layout_handle = set_layout;
VkDescriptorSetLayout layouts[2] = {set_layout_handle, set_layout_handle};
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 2;
allocate_info.pSetLayouts = layouts;
VkDescriptorSet descriptor_sets[2];
vk::AllocateDescriptorSets(device(), &allocate_info, descriptor_sets);
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
VkDescriptorBufferInfo buffer_info = {buffer, 0, VK_WHOLE_SIZE};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_sets[0];
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = &buffer_info;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
VkCopyDescriptorSet copy_set = vku::InitStructHelper();
copy_set.srcSet = descriptor_sets[1];
copy_set.srcBinding = 1;
copy_set.dstSet = descriptor_sets[0];
copy_set.dstBinding = 0;
copy_set.descriptorCount = 1;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-dstSet-04614");
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_set);
m_errorMonitor->VerifyFound();
}
{
VkDescriptorType descriptor_types[] = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_SAMPLER};
VkMutableDescriptorTypeListEXT mutable_descriptor_type_lists[2] = {{2, descriptor_types}, {0, nullptr}};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 2;
mdtci.pMutableDescriptorTypeLists = mutable_descriptor_type_lists;
VkDescriptorPoolSize pool_sizes[3] = {
{VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 4}, {VK_DESCRIPTOR_TYPE_SAMPLER, 4}, {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 4}};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(&mdtci);
ds_pool_ci.maxSets = 2;
ds_pool_ci.poolSizeCount = 2;
ds_pool_ci.pPoolSizes = pool_sizes;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding bindings[2] = {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 2, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr}};
VkDescriptorSetLayoutCreateInfo create_info = vku::InitStructHelper(&mdtci);
create_info.bindingCount = 2;
create_info.pBindings = bindings;
vkt::DescriptorSetLayout set_layout(*m_device, create_info);
VkDescriptorSetLayout set_layout_handle = set_layout;
VkDescriptorSetLayout layouts[2] = {set_layout_handle, set_layout_handle};
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 2;
allocate_info.pSetLayouts = layouts;
VkDescriptorSet descriptor_sets[2];
vk::AllocateDescriptorSets(device(), &allocate_info, descriptor_sets);
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkDescriptorBufferInfo buffer_info = {buffer, 0, VK_WHOLE_SIZE};
VkDescriptorImageInfo image_info = {sampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_sets[0];
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptor_write.pImageInfo = &image_info;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
descriptor_write.dstArrayElement = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = &buffer_info;
descriptor_write.pImageInfo = nullptr;
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
VkCopyDescriptorSet copy_set = vku::InitStructHelper();
copy_set.srcSet = descriptor_sets[0];
copy_set.srcBinding = 0;
copy_set.srcArrayElement = 0;
copy_set.dstSet = descriptor_sets[1];
copy_set.dstBinding = 1;
copy_set.dstArrayElement = 0;
copy_set.descriptorCount = 2;
// copying both mutables should fail because element 1 is the wrong type
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcSet-04613");
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_set);
m_errorMonitor->VerifyFound();
// copying element 0 should work
copy_set.descriptorCount = 1;
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_set);
// copying element 1 fail because it is the wrong type
copy_set.srcArrayElement = 1;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcSet-04613");
vk::UpdateDescriptorSets(device(), 0, nullptr, 1, &copy_set);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDescriptors, InvalidDescriptorSetLayoutInlineUniformBlockFlags) {
TEST_DESCRIPTION("Create descriptor set layout with invalid flags.");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::inlineUniformBlock);
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding binding{0, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 4, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorBindingFlags binding_flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags_ci = vku::InitStructHelper();
binding_flags_ci.bindingCount = 1u;
binding_flags_ci.pBindingFlags = &binding_flags;
VkDescriptorSetLayoutCreateInfo layout_ci = vku::InitStructHelper(&binding_flags_ci);
layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
layout_ci.bindingCount = 1u;
layout_ci.pBindings = &binding;
VkDescriptorSetLayout set_layout;
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingInlineUniformBlockUpdateAfterBind-02211");
vk::CreateDescriptorSetLayout(*m_device, &layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DispatchWithUnboundSet) {
TEST_DESCRIPTION("Dispatch with unbound descriptor set");
RETURN_IF_SKIP(Init());
const char *cs_source = R"glsl(
#version 450
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(set = 0, binding = 0) uniform sampler2D InputTexture;
layout(set = 1, binding = 0, rgba32f) uniform image2D OutputTexture;
void main() {
vec4 value = textureGather(InputTexture, vec2(0), 0);
imageStore(OutputTexture, ivec2(0), value);
}
)glsl";
OneOffDescriptorSet combined_image_set(
m_device, {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}});
OneOffDescriptorSet storage_image_set(m_device,
{{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}});
const VkFormat combined_image_format = VK_FORMAT_R8G8B8A8_UNORM;
vkt::Image image(*m_device, 1, 1, combined_image_format, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT);
cs_pipeline.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&combined_image_set.layout_, &storage_image_set.layout_});
cs_pipeline.CreateComputePipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cs_pipeline);
combined_image_set.WriteDescriptorImageInfo(0, view, sampler);
combined_image_set.UpdateDescriptorSets();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cs_pipeline.pipeline_layout_, 0, 1,
&combined_image_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08600");
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, CompatiblePushConstantRanges) {
RETURN_IF_SKIP(Init());
const char *shader_source = R"glsl(
#version 460
layout(push_constant, std430) uniform PC {
uint b;
} pc;
layout(set = 0, binding = 0) buffer SSBO {
uint x;
} ssbo;
void main() {
ssbo.x = pc.b;
}
)glsl";
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
vkt::Buffer ssbo_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
descriptor_set.WriteDescriptorBufferInfo(0, ssbo_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const vkt::PipelineLayout pipeline_layout_a(*m_device, {&descriptor_set.layout_});
VkPushConstantRange pc_range = {VK_SHADER_STAGE_COMPUTE_BIT, 0, 16};
const vkt::PipelineLayout pipeline_layout_b(*m_device, {&descriptor_set.layout_}, {pc_range});
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, shader_source, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.cp_ci_.layout = pipeline_layout_b;
pipe.CreateComputePipeline();
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_a, 0u, 1u, &descriptor_set.set_, 0u,
nullptr);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
uint32_t data = 0;
vk::CmdPushConstants(m_command_buffer, pipeline_layout_b, VK_SHADER_STAGE_COMPUTE_BIT, 0, 4, &data);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08600");
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, InvalidDescriptorSetLayoutFlags) {
TEST_DESCRIPTION("Create descriptor set layout with invalid flags.");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding binding{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorBindingFlags binding_flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags_ci = vku::InitStructHelper();
binding_flags_ci.bindingCount = 1u;
binding_flags_ci.pBindingFlags = &binding_flags;
VkDescriptorSetLayoutCreateInfo layout_ci = vku::InitStructHelper(&binding_flags_ci);
layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
layout_ci.bindingCount = 1u;
layout_ci.pBindings = &binding;
VkDescriptorSetLayout set_layout;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-None-03011");
vk::CreateDescriptorSetLayout(*m_device, &layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, SampledImageDepthComparisonForFormat) {
TEST_DESCRIPTION("Verify that OpImage*Dref* operations are supported for given format ");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkFormat format = VK_FORMAT_UNDEFINED;
for (uint32_t fmt = VK_FORMAT_R4G4_UNORM_PACK8; fmt < VK_FORMAT_D16_UNORM; fmt++) {
VkFormatProperties3 fmt_props_3 = vku::InitStructHelper();
VkFormatProperties2 fmt_props = vku::InitStructHelper(&fmt_props_3);
vk::GetPhysicalDeviceFormatProperties2KHR(Gpu(), (VkFormat)fmt, &fmt_props);
const bool has_sampling = (fmt_props_3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT) != 0;
const bool has_sampling_img_depth_compare =
(fmt_props_3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT) != 0;
if (has_sampling && !has_sampling_img_depth_compare) {
format = (VkFormat)fmt;
break;
}
}
if (format == VK_FORMAT_UNDEFINED) {
GTEST_SKIP() << "Cannot find suitable format, skipping.";
}
const char vsSource[] = R"glsl(
#version 450
void main() {
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
const char fsSource[] = R"glsl(
#version 450
layout (set = 0, binding = 1) uniform sampler2DShadow tex;
void main() {
float f = texture(tex, vec3(0));
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper g_pipe(*this);
g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
g_pipe.dsl_bindings_[0] = {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
g_pipe.CreateGraphicsPipeline();
vkt::Image image(*m_device, 32, 32, format, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
g_pipe.descriptor_set_->WriteDescriptorImageInfo(1, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
g_pipe.descriptor_set_->UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_, 0, 1,
&g_pipe.descriptor_set_->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-06479");
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, BindDescriptorWithoutPipelineLayout) {
TEST_DESCRIPTION("Bind a DescriptorSet with a null pipeline layout.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
m_errorMonitor->SetDesiredError("UNASSIGNED-GeneralParameterError-RequiredHandle");
VkPipelineLayout null_layout = CastFromUint64<VkPipelineLayout>(0);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, null_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, InvalidImageInfoDescriptorType) {
TEST_DESCRIPTION("Try to copy a descriptor set where the src and dst have different update after bind flags.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageCreateInfo image_ci = vku::InitStructHelper();
image_ci.flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT | VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT;
image_ci.imageType = VK_IMAGE_TYPE_3D;
image_ci.format = format;
image_ci.extent = {32, 32, 2};
image_ci.mipLevels = 1u;
image_ci.arrayLayers = 1u;
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
image_ci.usage = VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vkt::Image image(*m_device, image_ci, vkt::set_layout);
vkt::ImageView view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 0, 1);
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-VkDescriptorImageInfo-imageView-07795");
descriptor_set.WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_IMAGE_LAYOUT_GENERAL);
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, CopyDescriptorSetMissingSrcFlag) {
TEST_DESCRIPTION("Try to copy a descriptor set where the src and dst have different update after bind flags.");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet src_descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, VK_SHADER_STAGE_ALL, nullptr},
},
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, nullptr,
VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT);
OneOffDescriptorSet dst_descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, VK_SHADER_STAGE_ALL, nullptr},
},
0u, nullptr, VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT);
OneOffDescriptorSet no_flags_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, VK_SHADER_STAGE_ALL, nullptr},
},
0u, nullptr, 0u);
VkCopyDescriptorSet copy_descriptor_set = vku::InitStructHelper();
copy_descriptor_set.srcSet = src_descriptor_set.set_;
copy_descriptor_set.srcBinding = 0u;
copy_descriptor_set.srcArrayElement = 0u;
copy_descriptor_set.dstSet = dst_descriptor_set.set_;
copy_descriptor_set.dstBinding = 0u;
copy_descriptor_set.dstArrayElement = 0u;
copy_descriptor_set.descriptorCount = 1u;
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcSet-01918");
vk::UpdateDescriptorSets(*m_device, 0u, nullptr, 1u, &copy_descriptor_set);
m_errorMonitor->VerifyFound();
copy_descriptor_set.srcSet = dst_descriptor_set.set_;
copy_descriptor_set.dstSet = no_flags_set.set_;
m_errorMonitor->SetDesiredError("VUID-VkCopyDescriptorSet-srcSet-01920");
vk::UpdateDescriptorSets(*m_device, 0u, nullptr, 1u, &copy_descriptor_set);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, InvalidDescriptorWriteImageInfo) {
TEST_DESCRIPTION("Write descriptor set with invalid image info.");
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
m_errorMonitor->SetDesiredError("VUID-vkUpdateDescriptorSets-pDescriptorWrites-06493");
vk::UpdateDescriptorSets(*m_device, 1u, &descriptor_write, 0u, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, BindStorageBufferDynamicAlignment) {
TEST_DESCRIPTION("Bind dynamic storage buffer with invalid alignment.");
RETURN_IF_SKIP(Init());
uint32_t alignment = static_cast<uint32_t>(m_device->Physical().limits_.minStorageBufferOffsetAlignment);
if (alignment < 2) {
GTEST_SKIP() << "minStorageBufferOffsetAlignment too small";
}
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
uint32_t dynamic_offset = alignment - 1;
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &descriptor_set.set_, 1u,
&dynamic_offset);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DescriptorIndexingMissingFeatures) {
TEST_DESCRIPTION("Use partially bound descriptor flag without feature.");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkDescriptorBindingFlags flag = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT;
VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = 1u;
flags_create_info.pBindingFlags = &flag;
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 10, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&flags_create_info);
ds_layout_ci.bindingCount = 1u;
ds_layout_ci.pBindings = &binding;
VkDescriptorSetLayout set_layout;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingPartiallyBound-03013");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
flag = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingSampledImageUpdateAfterBind-03006");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingStorageImageUpdateAfterBind-03007");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingStorageBufferUpdateAfterBind-03008");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingStorageTexelBufferUpdateAfterBind-03010");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingUniformTexelBufferUpdateAfterBind-03009");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
flag = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT;
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingUpdateUnusedWhilePending-03012");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
flag = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT;
m_errorMonitor->SetDesiredError(
"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingVariableDescriptorCount-03014");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, IncompatibleDescriptorFlagsWithBindingFlags) {
TEST_DESCRIPTION("Create descriptor set layout with incompatible flags with binding flags");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount);
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding bindings[2] = {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}};
VkDescriptorBindingFlags binding_flags[] = {VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, 0};
VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = 1u;
flags_create_info.pBindingFlags = binding_flags;
VkDescriptorSetLayoutCreateInfo create_info = vku::InitStructHelper(&flags_create_info);
create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT;
create_info.bindingCount = 1u;
create_info.pBindings = bindings;
VkDescriptorSetLayout set_layout;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-flags-03003");
vk::CreateDescriptorSetLayout(*m_device, &create_info, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
create_info.flags = 0u;
flags_create_info.bindingCount = 2u;
create_info.bindingCount = 2u;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03004");
vk::CreateDescriptorSetLayout(*m_device, &create_info, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
flags_create_info.bindingCount = 1u;
create_info.bindingCount = 1u;
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03015");
vk::CreateDescriptorSetLayout(*m_device, &create_info, nullptr, &set_layout);
m_errorMonitor->VerifyFound();
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
uint32_t descriptorCounts[2] = {1u, 1u};
VkDescriptorSetVariableDescriptorCountAllocateInfo variable_allocate = vku::InitStructHelper();
variable_allocate.descriptorSetCount = 2u;
variable_allocate.pDescriptorCounts = descriptorCounts;
VkDescriptorPoolSize ds_type_count{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1u;
ds_pool_ci.poolSizeCount = 1u;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
const vkt::DescriptorSetLayout ds_layout(*m_device, {bindings[0]});
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper(&variable_allocate);
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 1u;
allocate_info.pSetLayouts = &ds_layout.handle();
VkDescriptorSet descriptor_set;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetVariableDescriptorCountAllocateInfo-descriptorSetCount-03045");
vk::AllocateDescriptorSets(*m_device, &allocate_info, &descriptor_set);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, MaxInlineUniformTotalSize) {
TEST_DESCRIPTION("Test the maxInlineUniformTotalSize limit");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::inlineUniformBlock);
AddRequiredFeature(vkt::Feature::geometryShader);
AddRequiredFeature(vkt::Feature::tessellationShader);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceInlineUniformBlockPropertiesEXT inline_uniform_block_properties = vku::InitStructHelper();
VkPhysicalDeviceVulkan13Properties properties13 = vku::InitStructHelper(&inline_uniform_block_properties);
GetPhysicalDeviceProperties2(properties13);
const uint32_t limit = properties13.maxInlineUniformTotalSize;
if (limit == vvl::kU32Max) {
GTEST_SKIP() << "maxInlineUniformTotalSize is too large";
}
const uint32_t binding_count = limit / inline_uniform_block_properties.maxInlineUniformBlockSize + 1;
std::vector<VkDescriptorSetLayoutBinding> bindings(binding_count);
const VkShaderStageFlags stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT,
VK_SHADER_STAGE_FRAGMENT_BIT};
for (uint32_t i = 0; i < binding_count; ++i) {
bindings[i].binding = i;
bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK;
bindings[i].descriptorCount = inline_uniform_block_properties.maxInlineUniformBlockSize;
bindings[i].stageFlags = stages[i % 5];
bindings[i].pImmutableSamplers = nullptr;
}
VkDescriptorSetLayoutCreateInfo set_layout_ci = vku::InitStructHelper();
set_layout_ci.bindingCount = binding_count;
set_layout_ci.pBindings = bindings.data();
vkt::DescriptorSetLayout set_layout(*m_device, set_layout_ci);
VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
pipeline_layout_ci.setLayoutCount = 1u;
pipeline_layout_ci.pSetLayouts = &set_layout.handle();
VkPipelineLayout pipeline_layout;
if (binding_count > inline_uniform_block_properties.maxDescriptorSetUpdateAfterBindInlineUniformBlocks) {
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02217");
}
if (binding_count / 5 > inline_uniform_block_properties.maxPerStageDescriptorInlineUniformBlocks) {
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02214");
}
if (binding_count / 5 > inline_uniform_block_properties.maxPerStageDescriptorInlineUniformBlocks) {
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02215");
}
if (binding_count > inline_uniform_block_properties.maxDescriptorSetInlineUniformBlocks) {
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02216");
}
m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-06531");
vk::CreatePipelineLayout(*m_device, &pipeline_layout_ci, nullptr, &pipeline_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorTypeNotInPool) {
TEST_DESCRIPTION("With maintenance1, allocate descriptor with type not in pool");
SetTargetApiVersion(VK_API_VERSION_1_1); // Need VK_KHR_maintenance1
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Create Pool with 2 Sampler descriptors, but try to alloc an Uniform Buffer
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_SAMPLER, 2};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 2;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding dsl_binding_sampler = {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorSetLayoutBinding dsl_binding_uniform = {1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr};
const vkt::DescriptorSetLayout ds_layout(*m_device, {dsl_binding_sampler, dsl_binding_uniform});
VkDescriptorSet descriptor_set;
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 1;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = &ds_layout.handle();
m_errorMonitor->SetDesiredWarning("WARNING-CoreValidation-AllocateDescriptorSets-WrongType");
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_set);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DescriptorTypeNotInPool2) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9662");
SetTargetApiVersion(VK_API_VERSION_1_1); // Need VK_KHR_maintenance1
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &ds_type_count;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
VkDescriptorSetLayoutBinding ds_layout_binding0 = {0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT,
nullptr};
VkDescriptorSetLayoutBinding ds_layout_binding1 = {1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT,
nullptr};
const vkt::DescriptorSetLayout ds_layout(*m_device, {ds_layout_binding0, ds_layout_binding1});
VkDescriptorSet descriptor_set;
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 1;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = &ds_layout.handle();
m_errorMonitor->SetDesiredWarning("WARNING-CoreValidation-AllocateDescriptorSets-WrongType");
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_set);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, PushDescriptorWithoutInfo) {
TEST_DESCRIPTION("Push a descriptor without providing any info structs in VkWriteDescriptorSet");
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
},
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT);
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
m_command_buffer.Begin();
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
m_errorMonitor->SetDesiredError("VUID-vkCmdPushDescriptorSet-pDescriptorWrites-06494");
vk::CmdPushDescriptorSetKHR(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &descriptor_write);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, GetSupportMutableDescriptorType) {
TEST_DESCRIPTION("Test vkGetDescriptorSetLayoutSupport with mutable descriptor set layout support");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo set_layout_ci = vku::InitStructHelper();
set_layout_ci.bindingCount = 1;
set_layout_ci.pBindings = &binding;
VkDescriptorSetLayoutSupport support = vku::InitStructHelper();
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutCreateInfo-pBindings-07303");
vk::GetDescriptorSetLayoutSupport(device(), &set_layout_ci, &support);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, EmptyDescriptorSetLayout) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8065");
RETURN_IF_SKIP(Init());
// Layout is created with no bindings
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
VkDescriptorPoolSize pool_sizes = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1;
ds_pool_ci.poolSizeCount = 1;
ds_pool_ci.pPoolSizes = &pool_sizes;
vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci);
VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.descriptorSetCount = 1;
alloc_info.descriptorPool = ds_pool;
alloc_info.pSetLayouts = &ds_layout.handle();
VkDescriptorSet descriptor_set;
vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_set);
vkt::Buffer buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buff_info = {buffer, 0, VK_WHOLE_SIZE};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.pBufferInfo = &buff_info;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.dstSet = descriptor_set;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-dstBinding-10009");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, DuplicateLayoutDifferentSampler) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8497");
RETURN_IF_SKIP(Init());
auto sampler_ci = SafeSaneSamplerCreateInfo();
vkt::Sampler sampler_0(*m_device, sampler_ci);
sampler_ci.maxLod = 8.0;
vkt::Sampler sampler_1(*m_device, sampler_ci);
OneOffDescriptorSet ds_0(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, &sampler_0.handle()}});
const vkt::PipelineLayout pipeline_layout_0(*m_device, {&ds_0.layout_});
OneOffDescriptorSet ds_1(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, &sampler_1.handle()}});
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_0, 0, 1, &ds_1.set_, 0, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DuplicateLayoutDifferentSampler2) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance4);
RETURN_IF_SKIP(Init());
auto sampler_ci = SafeSaneSamplerCreateInfo();
vkt::Sampler sampler_0(*m_device, sampler_ci);
sampler_ci.maxLod = 8.0;
vkt::Sampler sampler_1(*m_device, sampler_ci);
OneOffDescriptorSet ds_0(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, &sampler_0.handle()}});
const vkt::PipelineLayout pipeline_layout_0(*m_device, {&ds_0.layout_});
OneOffDescriptorSet ds_1(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, &sampler_1.handle()}});
sampler_1.Destroy();
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_0, 0, 1, &ds_1.set_, 0, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DuplicateLayoutDifferentSamplerArray) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8497");
RETURN_IF_SKIP(Init());
auto sampler_ci = SafeSaneSamplerCreateInfo();
vkt::Sampler sampler_0(*m_device, sampler_ci);
sampler_ci.maxLod = 8.0;
vkt::Sampler sampler_1(*m_device, sampler_ci);
VkSampler sampler_array_0[3] = {sampler_0, sampler_0, sampler_0};
VkSampler sampler_array_1[3] = {sampler_0, sampler_1, sampler_0};
OneOffDescriptorSet ds_0(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3, VK_SHADER_STAGE_COMPUTE_BIT, sampler_array_0}});
const vkt::PipelineLayout pipeline_layout_0(*m_device, {&ds_0.layout_});
OneOffDescriptorSet ds_1(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3, VK_SHADER_STAGE_COMPUTE_BIT, sampler_array_1}});
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358");
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_0, 0, 1, &ds_1.set_, 0, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, DSBufferLimitWithTemplateUpdate) {
AddRequiredExtensions(VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const VkDeviceSize storage_buffer_offset_alignment = m_device->Physical().limits_.minStorageBufferOffsetAlignment;
vkt::Buffer buffer(*m_device, 16u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
});
VkDescriptorBufferInfo buffer_info = {buffer, storage_buffer_offset_alignment / 2u, VK_WHOLE_SIZE};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.descriptorCount = 1u;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptor_write.pBufferInfo = &buffer_info;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00328");
vk::UpdateDescriptorSets(device(), 1u, &descriptor_write, 0, NULL);
m_errorMonitor->VerifyFound();
VkDescriptorUpdateTemplateEntry templateEntry;
templateEntry.dstBinding = 0u;
templateEntry.dstArrayElement = 0u;
templateEntry.descriptorCount = 1u;
templateEntry.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
templateEntry.offset = 0u;
templateEntry.stride = sizeof(VkDescriptorBufferInfo);
VkDescriptorUpdateTemplateCreateInfo template_create_info = vku::InitStructHelper();
template_create_info.descriptorUpdateEntryCount = 1u;
template_create_info.pDescriptorUpdateEntries = &templateEntry;
template_create_info.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
template_create_info.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate descriptor_update_template(*m_device, template_create_info);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00328");
vk::UpdateDescriptorSetWithTemplateKHR(device(), descriptor_set.set_, descriptor_update_template, &buffer_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, UpdateDescriptorSetWithAccelerationStructure) {
TEST_DESCRIPTION("Update descriptor set with invalid acceleration structures.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
VkDescriptorPoolSize pool_size{VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1};
VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper();
ds_pool_ci.maxSets = 1u;
ds_pool_ci.poolSizeCount = 1u;
ds_pool_ci.pPoolSizes = &pool_size;
vkt::DescriptorPool pool(*m_device, ds_pool_ci);
vkt::DescriptorSetLayout set_layout(*m_device,
{0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_ALL, nullptr});
VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper();
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = 1u;
allocate_info.pSetLayouts = &set_layout.handle();
VkDescriptorSet descriptor_set;
vk::AllocateDescriptorSets(device(), &allocate_info, &descriptor_set);
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set;
descriptor_write.dstBinding = 0u;
descriptor_write.descriptorCount = 1u;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02382");
vk::UpdateDescriptorSets(device(), 1u, &descriptor_write, 0u, nullptr);
m_errorMonitor->VerifyFound();
auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
blas->Create();
VkAccelerationStructureKHR null_acceleration_structure = VK_NULL_HANDLE;
VkWriteDescriptorSetAccelerationStructureKHR blas_descriptor = vku::InitStructHelper();
blas_descriptor.accelerationStructureCount = 1u;
blas_descriptor.pAccelerationStructures = &null_acceleration_structure;
descriptor_write.pNext = &blas_descriptor;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSetAccelerationStructureKHR-pAccelerationStructures-03580");
vk::UpdateDescriptorSets(device(), 1u, &descriptor_write, 0u, nullptr);
m_errorMonitor->VerifyFound();
blas_descriptor.pAccelerationStructures = &blas->handle();
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSetAccelerationStructureKHR-pAccelerationStructures-03579");
vk::UpdateDescriptorSets(device(), 1u, &descriptor_write, 0u, nullptr);
m_errorMonitor->VerifyFound();
blas_descriptor.accelerationStructureCount = 0u;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSetAccelerationStructureKHR-accelerationStructureCount-arraylength");
vk::UpdateDescriptorSets(device(), 1u, &descriptor_write, 0u, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, AccelerationStructureTemplates) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7472");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_ALL, nullptr},
});
{
struct SimpleTemplateData {
VkAccelerationStructureKHR as;
};
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
update_template_entry.offset = 0;
update_template_entry.stride = sizeof(SimpleTemplateData);
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate update_template(*m_device, update_template_ci);
SimpleTemplateData update_template_data;
update_template_data.as = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSetAccelerationStructureKHR-pAccelerationStructures-03580");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
auto tlas = vkt::as::blueprint::AccelStructSimpleOnDeviceTopLevel(*m_device, 4096);
tlas->Create();
tlas->Destroy();
update_template_data.as = tlas->handle();
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSetAccelerationStructureKHR-pAccelerationStructures-03580");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
}
{
struct SimpleTemplateData {
VkWriteDescriptorSetAccelerationStructureKHR as_info; // wrong, should be VkAccelerationStructureKHR
};
auto tlas = vkt::as::blueprint::AccelStructSimpleOnDeviceTopLevel(*m_device, 4096);
tlas->Create();
VkWriteDescriptorSetAccelerationStructureKHR as_descriptor = vku::InitStructHelper();
as_descriptor.accelerationStructureCount = 1;
as_descriptor.pAccelerationStructures = &tlas->handle();
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
update_template_entry.offset = 0;
update_template_entry.stride = sizeof(SimpleTemplateData);
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate update_template(*m_device, update_template_ci);
SimpleTemplateData update_template_data;
update_template_data.as_info = as_descriptor;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSetAccelerationStructureKHR-pAccelerationStructures-03580");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDescriptors, TemplatesInvalidBuffer) {
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
struct SimpleTemplateData {
VkDescriptorBufferInfo buffer_info;
};
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
update_template_entry.offset = 0;
update_template_entry.stride = 0;
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate update_template(*m_device, update_template_ci);
VkBuffer invalid_handle = CastToHandle<VkBuffer, uintptr_t>(0xbaadbeef);
SimpleTemplateData update_template_data;
update_template_data.buffer_info = {invalid_handle, 0, VK_WHOLE_SIZE};
m_errorMonitor->SetDesiredError("VUID-VkDescriptorBufferInfo-buffer-parameter");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, TemplatesInvalidBufferView) {
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
struct SimpleTemplateData {
VkBufferView buffer_view;
};
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
update_template_entry.offset = 0;
update_template_entry.stride = 0;
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate update_template(*m_device, update_template_ci);
VkBufferView invalid_handle = CastToHandle<VkBufferView, uintptr_t>(0xbaadbeef);
SimpleTemplateData update_template_data;
update_template_data.buffer_view = invalid_handle;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02994");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, TemplatesInvalidStorageImage) {
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}});
struct SimpleTemplateData {
VkDescriptorImageInfo image_info;
};
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
update_template_entry.offset = 0;
update_template_entry.stride = 0;
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate update_template(*m_device, update_template_ci);
VkImageView invalid_handle = CastToHandle<VkImageView, uintptr_t>(0xbaadbeef);
SimpleTemplateData update_template_data;
update_template_data.image_info = {VK_NULL_HANDLE, invalid_handle, VK_IMAGE_LAYOUT_GENERAL};
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02996");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, TemplatesInvalidSampler) {
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}});
struct SimpleTemplateData {
VkDescriptorImageInfo image_info;
};
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
update_template_entry.offset = 0;
update_template_entry.stride = 0;
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate update_template(*m_device, update_template_ci);
VkSampler invalid_handle = CastToHandle<VkSampler, uintptr_t>(0xbaadbeef);
SimpleTemplateData update_template_data;
update_template_data.image_info = {invalid_handle, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_GENERAL};
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00325");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, TemplatesInvalidCombinedImageSampler) {
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}});
struct SimpleTemplateData {
VkDescriptorImageInfo image_info;
};
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
update_template_entry.offset = 0;
update_template_entry.stride = 0;
VkDescriptorUpdateTemplateCreateInfo update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
update_template_ci.descriptorSetLayout = descriptor_set.layout_;
vkt::DescriptorUpdateTemplate update_template(*m_device, update_template_ci);
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView image_view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkSampler invalid_sampler = CastToHandle<VkSampler, uintptr_t>(0xbaadbeef);
VkImageView invalid_view = CastToHandle<VkImageView, uintptr_t>(0xbaadbeee);
SimpleTemplateData update_template_data;
update_template_data.image_info = {invalid_sampler, image_view, VK_IMAGE_LAYOUT_GENERAL};
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00325");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
update_template_data.image_info = {sampler, invalid_view, VK_IMAGE_LAYOUT_GENERAL};
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02996");
vk::UpdateDescriptorSetWithTemplate(device(), descriptor_set.set_, update_template, &update_template_data);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, InvalidCombinedImageSampler) {
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}});
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView image_view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkSampler invalid_sampler = CastToHandle<VkSampler, uintptr_t>(0xbaadbeef);
VkImageView invalid_view = CastToHandle<VkImageView, uintptr_t>(0xbaadbeee);
descriptor_set.WriteDescriptorImageInfo(0, image_view, invalid_sampler);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00325");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
descriptor_set.Clear();
descriptor_set.WriteDescriptorImageInfo(0, invalid_view, sampler);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02996");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, PartitionedAccelerationStructureTypeMismatch) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
// Try to update with VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV when the layout expects UNIFORM_BUFFER
VkWriteDescriptorSetPartitionedAccelerationStructureNV accel_struct_info = vku::InitStructHelper();
accel_struct_info.accelerationStructureCount = 1;
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper(&accel_struct_info);
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV;
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-00319");
vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDescriptors, ImmutableSamplerIdenticallyDefined) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10098");
RETURN_IF_SKIP(Init());
vkt::Buffer storage_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkt::Image image(*m_device, 16, 16, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkt::ImageView image_view = image.CreateView();
VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
sampler_ci.maxLod = 16.0;
vkt::Sampler sampler1(*m_device, sampler_ci);
sampler_ci.maxLod = 8.0;
vkt::Sampler sampler2(*m_device, sampler_ci);
std::vector<VkDescriptorSetLayoutBinding> binding_defs = {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler1.handle()},
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
};
const vkt::DescriptorSetLayout pipeline_dsl(*m_device, binding_defs);
const vkt::PipelineLayout pipeline_layout(*m_device, {&pipeline_dsl});
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler2.handle()},
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout binding_pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char *csSource = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { vec4 dummy; };
layout(set = 0, binding = 1) uniform sampler s;
layout(set = 0, binding = 2) uniform texture2D t;
void main() {
dummy = texture(sampler2D(t, s), vec2(0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, binding_pipeline_layout, 0, 1, &descriptor_set.set_,
0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08600");
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, ImmutableSamplerIdenticallyDefinedMaintenance4) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10098");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance4);
RETURN_IF_SKIP(Init());
vkt::Buffer storage_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkt::Image image(*m_device, 16, 16, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkt::ImageView image_view = image.CreateView();
VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
sampler_ci.maxLod = 16.0;
vkt::Sampler sampler1(*m_device, sampler_ci);
sampler_ci.maxLod = 8.0;
vkt::Sampler sampler2(*m_device, sampler_ci);
std::vector<VkDescriptorSetLayoutBinding> binding_defs = {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler1.handle()},
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
};
vkt::DescriptorSetLayout pipeline_dsl(*m_device, binding_defs);
vkt::PipelineLayout pipeline_layout(*m_device, {&pipeline_dsl});
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler2.handle()},
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout binding_pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char *csSource = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { vec4 dummy; };
layout(set = 0, binding = 1) uniform sampler s;
layout(set = 0, binding = 2) uniform texture2D t;
void main() {
dummy = texture(sampler2D(t, s), vec2(0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline();
// VK_KHR_maintenance4 lets us destroy this after creating the pipeline
pipeline_layout.Destroy();
sampler1.Destroy();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, binding_pipeline_layout, 0, 1, &descriptor_set.set_,
0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08600");
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDescriptors, ImmutableSamplerIdenticallyDefinedFilterMinmax) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10098");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::samplerFilterMinmax);
RETURN_IF_SKIP(Init());
vkt::Buffer storage_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkt::Image image(*m_device, 16, 16, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkt::ImageView image_view = image.CreateView();
VkSamplerReductionModeCreateInfo sampler_reduction_ci = vku::InitStructHelper();
sampler_reduction_ci.reductionMode = VK_SAMPLER_REDUCTION_MODE_MIN;
VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
sampler_ci.pNext = &sampler_reduction_ci;
vkt::Sampler sampler1(*m_device, sampler_ci);
sampler_reduction_ci.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
vkt::Sampler sampler2(*m_device, sampler_ci);
std::vector<VkDescriptorSetLayoutBinding> binding_defs = {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler1.handle()},
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
};
const vkt::DescriptorSetLayout pipeline_dsl(*m_device, binding_defs);
const vkt::PipelineLayout pipeline_layout(*m_device, {&pipeline_dsl});
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler2.handle()},
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout binding_pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char *csSource = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { vec4 dummy; };
layout(set = 0, binding = 1) uniform sampler s;
layout(set = 0, binding = 2) uniform texture2D t;
void main() {
dummy = texture(sampler2D(t, s), vec2(0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, binding_pipeline_layout, 0, 1, &descriptor_set.set_,
0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08600");
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}