| /* |
| * Copyright (c) 2026 Valve Corporation |
| * Copyright (c) 2026 LunarG, Inc. |
| * |
| * 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 "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| #include "../framework/buffer_helper.h" |
| #include "test_framework.h" |
| #include "utils/math_utils.h" |
| |
| class NegativeGpuAVDescriptorBuffer : public GpuAVDescriptorBuffer {}; |
| |
| // TODO - Add support in GPU-AV for this |
| TEST_F(NegativeGpuAVDescriptorBuffer, DISABLED_BasicNoDescriptor) { |
| TEST_DESCRIPTION("Never even call vkGetDescriptorEXT and try to access something"); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer({})); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| }; |
| |
| void main() { |
| a = 0; |
| } |
| )glsl"; |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper(); |
| allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| vkt::Buffer descriptor_buffer(*m_device, 1024, |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | |
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, |
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_flag_info); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDeviceSize buffer_address = Align(descriptor_buffer.Address(), descriptor_buffer_properties.descriptorBufferOffsetAlignment); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = buffer_address; |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| // TODO - Add support in GPU-AV for this |
| TEST_F(NegativeGpuAVDescriptorBuffer, DISABLED_BasicDescriptorWrongAddress) { |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer({})); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| }; |
| |
| void main() { |
| a = 0; |
| } |
| )glsl"; |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, ssbo_buffer, 16u); |
| |
| vkt::Buffer src_buffer(*m_device, 1024, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, |
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); |
| uint8_t* mapped_descriptor_data = (uint8_t*)src_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper(); |
| allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| vkt::Buffer descriptor_buffer(*m_device, 1024, |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | |
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, |
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_flag_info); |
| |
| m_command_buffer.Begin(); |
| // Put a descriptor twice in the wrong spot |
| VkBufferCopy buffer_copy = {0, 0, descriptor_buffer_properties.storageBufferDescriptorSize}; |
| vk::CmdCopyBuffer(m_command_buffer, src_buffer, descriptor_buffer, 1u, &buffer_copy); |
| buffer_copy.dstOffset = 256; |
| vk::CmdCopyBuffer(m_command_buffer, src_buffer, descriptor_buffer, 1u, &buffer_copy); |
| m_command_buffer.FullMemoryBarrier(); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| // somewhere randomly bad |
| VkDeviceSize buffer_address = |
| Align(descriptor_buffer.Address() + 512, descriptor_buffer_properties.descriptorBufferOffsetAlignment); |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = buffer_address; |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| // TODO - Add support in GPU-AV for this |
| TEST_F(NegativeGpuAVDescriptorBuffer, DISABLED_PostProcesingOnly) { |
| std::vector<VkLayerSettingEXT> layer_settings = { |
| {OBJECT_LAYER_NAME, "gpuav_descriptor_checks", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse}, |
| {OBJECT_LAYER_NAME, "gpuav_buffer_address_oob", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse}, |
| {OBJECT_LAYER_NAME, "gpuav_vertex_attribute_fetch_oob", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse}, |
| }; |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBindingSampledImageUpdateAfterBind); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer(layer_settings)); |
| InitRenderTarget(); |
| |
| const char* fs_source = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform sampler3D s; |
| layout(location=0) out vec4 color; |
| void main() { |
| color = texture(s, vec3(0)); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, kVertexDrawPassthroughGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_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(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings = { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer( |
| *m_device, ds_layout_size, |
| VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| uint8_t* mapped_descriptor_data = (uint8_t*)descriptor_buffer.Memory().Map(); |
| |
| vkt::DescriptorGetInfo get_info_combined(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, sampler, image_view, |
| VK_IMAGE_LAYOUT_GENERAL); |
| vk::GetDescriptorEXT(device(), get_info_combined, descriptor_buffer_properties.combinedImageSamplerDescriptorSize, |
| mapped_descriptor_data); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| 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); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = |
| VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-viewType-07752"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |