diff --git a/layers/state_tracker/descriptor_sets.cpp b/layers/state_tracker/descriptor_sets.cpp index b4d96a2eea0..cce2281f4c1 100644 --- a/layers/state_tracker/descriptor_sets.cpp +++ b/layers/state_tracker/descriptor_sets.cpp @@ -1151,7 +1151,7 @@ void vvl::MutableDescriptor::WriteUpdate(DescriptorSet &set_state, const Validat void vvl::MutableDescriptor::CopyUpdate(DescriptorSet &set_state, const ValidationStateTracker &dev_data, const Descriptor &src, bool is_bindless, VkDescriptorType src_type) { - VkDeviceSize src_size = 0; + VkDeviceSize buffer_size = 0; switch (src.GetClass()) { case DescriptorClass::PlainSampler: { auto &sampler_src = static_cast(src); @@ -1180,7 +1180,7 @@ void vvl::MutableDescriptor::CopyUpdate(DescriptorSet &set_state, const Validati case DescriptorClass::TexelBuffer: { ReplaceStatePtr(set_state, buffer_view_state_, static_cast(src).GetSharedBufferViewState(), is_bindless); - src_size = buffer_view_state_ ? buffer_view_state_->Size() : vvl::kU32Max; + buffer_size = buffer_view_state_ ? buffer_view_state_->Size() : vvl::kU32Max; break; } case DescriptorClass::GeneralBuffer: { @@ -1188,7 +1188,7 @@ void vvl::MutableDescriptor::CopyUpdate(DescriptorSet &set_state, const Validati offset_ = buff_desc.GetOffset(); range_ = buff_desc.GetRange(); ReplaceStatePtr(set_state, buffer_state_, buff_desc.GetSharedBufferState(), is_bindless); - src_size = range_; + buffer_size = range_; break; } case DescriptorClass::AccelerationStructure: { @@ -1250,45 +1250,20 @@ void vvl::MutableDescriptor::CopyUpdate(DescriptorSet &set_state, const Validati case DescriptorClass::Invalid: break; } - src_size = mutable_src.GetBufferSize(); + buffer_size = mutable_src.GetBufferSize(); break; } case vvl::DescriptorClass::InlineUniform: case vvl::DescriptorClass::Invalid: break; } - SetDescriptorType(src_type, src_size); + SetDescriptorType(src_type, buffer_size); } void vvl::MutableDescriptor::SetDescriptorType(VkDescriptorType type, VkDeviceSize buffer_size) { active_descriptor_type_ = type; buffer_size_ = buffer_size; } -void vvl::MutableDescriptor::SetDescriptorType(VkDescriptorType src_type, const Descriptor *src) { - active_descriptor_type_ = src_type; - if (src->GetClass() == vvl::DescriptorClass::GeneralBuffer) { - auto buffer = static_cast(src)->GetBuffer(); - if (buffer == VK_NULL_HANDLE) { - buffer_size_ = vvl::kU32Max; - } else { - auto buffer_state = static_cast(src)->GetBufferState(); - buffer_size_ = static_cast(buffer_state->create_info.size); - } - } else if (src->GetClass() == vvl::DescriptorClass::TexelBuffer) { - auto buffer_view = static_cast(src)->GetBufferView(); - if (buffer_view == VK_NULL_HANDLE) { - buffer_size_ = vvl::kU32Max; - } else { - auto buffer_view_state = static_cast(src)->GetBufferViewState(); - buffer_size_ = static_cast(buffer_view_state->buffer_state->create_info.size); - } - } else if (src->GetClass() == vvl::DescriptorClass::Mutable) { - auto descriptor = static_cast(src); - buffer_size_ = descriptor->GetBufferSize(); - } else { - buffer_size_ = 0; - } -} VkDeviceSize vvl::MutableDescriptor::GetEffectiveRange() const { // The buffer can be null if using nullDescriptors, if that is the case, the size/range will not be accessed @@ -1302,7 +1277,7 @@ VkDeviceSize vvl::MutableDescriptor::GetEffectiveRange() const { } void vvl::MutableDescriptor::UpdateDrawState(ValidationStateTracker *dev_data, vvl::CommandBuffer &cb_state) { - auto active_class = DescriptorTypeToClass(active_descriptor_type_); + const vvl::DescriptorClass active_class = ActiveClass(); if (active_class == DescriptorClass::Image || active_class == DescriptorClass::ImageSampler) { if (image_view_state_) { cb_state.SetImageViewInitialLayout(*image_view_state_, image_layout_); @@ -1312,7 +1287,7 @@ void vvl::MutableDescriptor::UpdateDrawState(ValidationStateTracker *dev_data, v bool vvl::MutableDescriptor::AddParent(StateObject *state_object) { bool result = false; - auto active_class = DescriptorTypeToClass(active_descriptor_type_); + const vvl::DescriptorClass active_class = ActiveClass(); switch (active_class) { case DescriptorClass::PlainSampler: if (sampler_state_) { diff --git a/layers/state_tracker/descriptor_sets.h b/layers/state_tracker/descriptor_sets.h index b4c3df31316..3b03e6c1d6b 100644 --- a/layers/state_tracker/descriptor_sets.h +++ b/layers/state_tracker/descriptor_sets.h @@ -589,7 +589,6 @@ class MutableDescriptor : public Descriptor { VkDescriptorType type) override; void SetDescriptorType(VkDescriptorType type, VkDeviceSize buffer_size); - void SetDescriptorType(VkDescriptorType src_type, const Descriptor *src); VkDeviceSize GetBufferSize() const { return buffer_size_; } std::shared_ptr GetSharedSamplerState() const { return sampler_state_; } diff --git a/tests/unit/descriptors.cpp b/tests/unit/descriptors.cpp index 7be1c16df16..0e59f0fd672 100644 --- a/tests/unit/descriptors.cpp +++ b/tests/unit/descriptors.cpp @@ -1488,6 +1488,54 @@ TEST_F(NegativeDescriptors, DISABLED_ConstantArrayElementNotBound) { 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 = {}; + type_list.descriptorTypeCount = 2; + type_list.pDescriptorTypes = 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_ = std::make_unique(this, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); + pipe.cp_ci_.layout = pipeline_layout.handle(); + pipe.CreateComputePipeline(); + + m_command_buffer.Begin(); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout.handle(), 0, 1, + &descriptor_set.set_, 0, NULL); + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08114"); + vk::CmdDispatch(m_command_buffer.handle(), 1, 1, 1); + m_errorMonitor->VerifyFound(); + m_command_buffer.End(); +} + TEST_F(NegativeDescriptors, UpdateDescriptorSetMismatchType) { RETURN_IF_SKIP(Init()); @@ -3579,11 +3627,7 @@ 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(InitFramework()); - VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT mutable_descriptor_type_features = vku::InitStructHelper(); - mutable_descriptor_type_features.mutableDescriptorType = VK_FALSE; - VkPhysicalDeviceFeatures2KHR features2 = vku::InitStructHelper(&mutable_descriptor_type_features); - RETURN_IF_SKIP(InitState(nullptr, &features2)); + RETURN_IF_SKIP(Init()); InitRenderTarget(); VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; diff --git a/tests/unit/gpu_av_descriptor_indexing.cpp b/tests/unit/gpu_av_descriptor_indexing.cpp index 000e2f4e8bc..8b7b01a8e0b 100644 --- a/tests/unit/gpu_av_descriptor_indexing.cpp +++ b/tests/unit/gpu_av_descriptor_indexing.cpp @@ -11,6 +11,7 @@ * http://www.apache.org/licenses/LICENSE-2.0 */ +#include #include "../framework/layer_validation_tests.h" #include "../framework/pipeline_helper.h" #include "../framework/descriptor_helper.h" @@ -1342,6 +1343,79 @@ TEST_F(NegativeGpuAVDescriptorIndexing, ImageArrayDynamicIndexing) { m_errorMonitor->VerifyFound(); } +// TODO - cb_state.image_layout_map is empty after updating a mutable descriptor +// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8918 +TEST_F(NegativeGpuAVDescriptorIndexing, DISABLED_ImageLayoutMutable) { + TEST_DESCRIPTION("Invalid image layout with mutable descriptors"); + AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::mutableDescriptorType); + RETURN_IF_SKIP(InitGpuVUDescriptorIndexing()); + + const char *cs = R"glsl( + #version 450 + layout(set=0, binding=0) uniform sampler2D s[2]; + layout(set=0, binding=1) buffer SSBO { uint index; }; + void main(){ + vec4 v = 2.0 * texture(s[index], vec2(0.0)); + } + )glsl"; + + vkt::Buffer storage_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); + uint32_t *storage_buffer_ptr = (uint32_t *)storage_buffer.Memory().Map(); + storage_buffer_ptr[0] = 1; + storage_buffer.Memory().Unmap(); + + VkDescriptorType desc_types[2] = { + VK_DESCRIPTOR_TYPE_SAMPLER, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + }; + + VkMutableDescriptorTypeListEXT type_list = {}; + type_list.descriptorTypeCount = 2; + type_list.pDescriptorTypes = desc_types; + + VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper(); + mdtci.mutableDescriptorTypeListCount = 1; + mdtci.pMutableDescriptorTypeLists = &type_list; + + OneOffDescriptorSet descriptor_set(m_device, + {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 2, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, + {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}}, + 0, &mdtci); + const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); + + CreateComputePipelineHelper pipe(*this); + pipe.cs_ = std::make_unique(this, cs, VK_SHADER_STAGE_COMPUTE_BIT); + pipe.cp_ci_.layout = pipeline_layout.handle(); + pipe.CreateComputePipeline(); + + const VkFormat fmt = VK_FORMAT_R8G8B8A8_UNORM; + vkt::Image image(*m_device, 64, 64, 1, fmt, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + image.SetLayout(VK_IMAGE_LAYOUT_GENERAL); + + vkt::ImageView view = image.CreateView(); + vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); + + descriptor_set.WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); + descriptor_set.WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); + descriptor_set.WriteDescriptorBufferInfo(1, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + descriptor_set.UpdateDescriptorSets(); + + m_command_buffer.Begin(); + vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout.handle(), 0, 1, + &descriptor_set.set_, 0, nullptr); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdDispatch(m_command_buffer.handle(), 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout"); + m_default_queue->Submit(m_command_buffer); + m_default_queue->Wait(); + m_errorMonitor->VerifyFound(); +} + TEST_F(NegativeGpuAVDescriptorIndexing, UpdateAfterBind) { TEST_DESCRIPTION("Exercise errors for updating a descriptor set after it is bound."); diff --git a/tests/unit/image.cpp b/tests/unit/image.cpp index 7e5ffd5707c..4c233b950eb 100644 --- a/tests/unit/image.cpp +++ b/tests/unit/image.cpp @@ -5271,6 +5271,67 @@ TEST_F(NegativeImage, ComputeImageLayout11) { m_errorMonitor->VerifyFound(); } +// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8918 +// This fails to create descriptor on RADV, might need to adjust OneOffDescriptorSet +TEST_F(NegativeImage, DISABLED_ImageLayoutMutable) { + TEST_DESCRIPTION("Invalid image layout with mutable descriptors"); + AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::mutableDescriptorType); + RETURN_IF_SKIP(Init()); + + const char *cs = R"glsl( + #version 450 + layout(set=0, binding=0) uniform sampler2D s; + void main(){ + vec4 v = 2.0 * texture(s, vec2(0.0)); + } + )glsl"; + + VkDescriptorType desc_types[2] = { + VK_DESCRIPTOR_TYPE_SAMPLER, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + }; + + VkMutableDescriptorTypeListEXT type_list = {}; + type_list.descriptorTypeCount = 2; + type_list.pDescriptorTypes = 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_}); + + CreateComputePipelineHelper pipe(*this); + pipe.cs_ = std::make_unique(this, cs, VK_SHADER_STAGE_COMPUTE_BIT); + pipe.cp_ci_.layout = pipeline_layout.handle(); + pipe.CreateComputePipeline(); + + const VkFormat fmt = VK_FORMAT_R8G8B8A8_UNORM; + vkt::Image image(*m_device, 64, 64, 1, fmt, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + image.SetLayout(VK_IMAGE_LAYOUT_GENERAL); + + vkt::ImageView view = image.CreateView(); + vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); + + descriptor_set.WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + descriptor_set.UpdateDescriptorSets(); + + m_command_buffer.Begin(); + vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout.handle(), 0, 1, + &descriptor_set.set_, 0, nullptr); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdDispatch(m_command_buffer.handle(), 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout"); + m_default_queue->Submit(m_command_buffer); + m_default_queue->Wait(); + m_errorMonitor->VerifyFound(); +} + TEST_F(NegativeImage, GetPhysicalDeviceImageFormatProperties) { TEST_DESCRIPTION("fail a call to GetPhysicalDeviceImageFormatProperties"); RETURN_IF_SKIP(Init()); diff --git a/tests/unit/object_lifetime.cpp b/tests/unit/object_lifetime.cpp index 6f7fa8adb2d..709df97b2af 100644 --- a/tests/unit/object_lifetime.cpp +++ b/tests/unit/object_lifetime.cpp @@ -353,6 +353,150 @@ TEST_F(NegativeObjectLifetime, CmdBufferBufferViewDestroyed) { m_errorMonitor->VerifyFound(); } +TEST_F(NegativeObjectLifetime, DescriptorSetStorageBufferDestroyed) { + RETURN_IF_SKIP(Init()); + + OneOffDescriptorSet descriptor_set(m_device, { + {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, + }); + const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); + + vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + descriptor_set.UpdateDescriptorSets(); + + 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_ = std::make_unique(this, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); + pipe.cp_ci_.layout = pipeline_layout.handle(); + pipe.CreateComputePipeline(); + + // Destroy the buffer before it's bound to the cmd buffer + buffer.destroy(); + + m_command_buffer.Begin(); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout.handle(), 0, 1, + &descriptor_set.set_, 0, NULL); + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08114"); + vk::CmdDispatch(m_command_buffer.handle(), 1, 1, 1); + m_errorMonitor->VerifyFound(); + m_command_buffer.End(); +} + +// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8918 +TEST_F(NegativeObjectLifetime, DISABLED_DescriptorSetMutableBufferDestroyed) { + 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 = {}; + type_list.descriptorTypeCount = 2; + type_list.pDescriptorTypes = 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); + descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + descriptor_set.UpdateDescriptorSets(); + + 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_ = std::make_unique(this, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); + pipe.cp_ci_.layout = pipeline_layout.handle(); + pipe.CreateComputePipeline(); + + buffer.destroy(); // Destroy the buffer before it's bound to the cmd buffer + + m_command_buffer.Begin(); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout.handle(), 0, 1, + &descriptor_set.set_, 0, NULL); + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08114"); + vk::CmdDispatch(m_command_buffer.handle(), 1, 1, 1); + m_errorMonitor->VerifyFound(); + m_command_buffer.End(); +} + +// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8918 +TEST_F(NegativeObjectLifetime, DISABLED_DescriptorSetMutableBufferArrayDestroyed) { + 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 = {}; + type_list.descriptorTypeCount = 2; + type_list.pDescriptorTypes = desc_types; + + VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper(); + mdtci.mutableDescriptorTypeListCount = 1; + mdtci.pMutableDescriptorTypeLists = &type_list; + + OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 2, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}}, 0, + &mdtci); + const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); + + vkt::Buffer storage_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // not used + vkt::Buffer uniform_buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); // used + descriptor_set.WriteDescriptorBufferInfo(0, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0); + descriptor_set.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); + descriptor_set.UpdateDescriptorSets(); + + const char *cs_source = R"glsl( + #version 450 + layout(set=0, binding=0) buffer SSBO { uint x; } ssbo[2]; + void main(){ + ssbo[1].x = 0; + } + )glsl"; + + CreateComputePipelineHelper pipe(*this); + pipe.cs_ = std::make_unique(this, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); + pipe.cp_ci_.layout = pipeline_layout.handle(); + pipe.CreateComputePipeline(); + + uniform_buffer.destroy(); // Destroy the buffer before it's bound to the cmd buffer + + m_command_buffer.Begin(); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout.handle(), 0, 1, + &descriptor_set.set_, 0, NULL); + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-08114"); + vk::CmdDispatch(m_command_buffer.handle(), 1, 1, 1); + m_errorMonitor->VerifyFound(); + m_command_buffer.End(); +} + TEST_F(NegativeObjectLifetime, CmdBufferImageDestroyed) { TEST_DESCRIPTION("Attempt to draw with a command buffer that is invalid due to an image dependency being destroyed."); RETURN_IF_SKIP(Init()) { diff --git a/tests/unit/object_lifetime_positive.cpp b/tests/unit/object_lifetime_positive.cpp index e9a99935cb8..e3a1a0bde02 100644 --- a/tests/unit/object_lifetime_positive.cpp +++ b/tests/unit/object_lifetime_positive.cpp @@ -14,6 +14,7 @@ #include "../framework/layer_validation_tests.h" #include "../framework/descriptor_helper.h" +#include "../framework/pipeline_helper.h" class PositiveObjectLifetime : public VkLayerTest {}; @@ -155,4 +156,60 @@ TEST_F(PositiveObjectLifetime, DescriptorBufferInfoCopy) { copy_ds_update.dstBinding = 0; copy_ds_update.descriptorCount = 1; vk::UpdateDescriptorSets(device(), 0, nullptr, 1, ©_ds_update); -} \ No newline at end of file +} + +TEST_F(PositiveObjectLifetime, DescriptorSetMutableBufferDestroyed) { + 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 = {}; + type_list.descriptorTypeCount = 2; + type_list.pDescriptorTypes = desc_types; + + VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper(); + mdtci.mutableDescriptorTypeListCount = 1; + mdtci.pMutableDescriptorTypeLists = &type_list; + + OneOffDescriptorSet descriptor_set0(m_device, {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}}, 0, + &mdtci); + OneOffDescriptorSet descriptor_set1(m_device, + {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}}); + const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set0.layout_, &descriptor_set1.layout_}); + + vkt::Buffer storage_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // used + descriptor_set0.WriteDescriptorBufferInfo(0, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + descriptor_set0.UpdateDescriptorSets(); + + vkt::Buffer uniform_buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); // not used + descriptor_set1.WriteDescriptorBufferInfo(0, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + descriptor_set1.UpdateDescriptorSets(); + + const char *cs_source = R"glsl( + #version 450 + layout(set=0, binding=0) buffer SSBO { uint x; }; + // layout(set=1, binding=0) uniform UBO { uint y; }; + void main(){ + x = 0; + } + )glsl"; + + CreateComputePipelineHelper pipe(*this); + pipe.cs_ = std::make_unique(this, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); + pipe.cp_ci_.layout = pipeline_layout.handle(); + pipe.CreateComputePipeline(); + + // uniform_buffer.destroy(); // Destroy the UNUSED buffer before it's bound to the cmd buffer + + m_command_buffer.Begin(); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout.handle(), 0, 1, + &descriptor_set0.set_, 0, nullptr); + vk::CmdDispatch(m_command_buffer.handle(), 1, 1, 1); + m_command_buffer.End(); +}