| /* |
| * Copyright (c) 2026 The Khronos Group Inc. |
| * 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 <cstdint> |
| #include <cstring> |
| #include <vector> |
| #include "descriptor_heap_object.h" |
| #include "generated/vk_function_pointers.h" |
| #include "layer_validation_tests.h" |
| #include "pipeline_helper.h" |
| #include "shader_object_helper.h" |
| #include "buffer_helper.h" |
| #include "utils/math_utils.h" |
| #include "gpuav/shaders/gpuav_shaders_constants.h" |
| #include "shader_helper.h" |
| #include "shader_templates.h" |
| #include "test_framework.h" |
| |
| class NegativeGpuAVDescriptorHeap : public GpuAVDescriptorHeap {}; |
| |
| // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12657 |
| TEST_F(NegativeGpuAVDescriptorHeap, DISABLED_IndexBufferOOB) { |
| TEST_DESCRIPTION("Validate overruning the index buffer"); |
| AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitRenderTarget(); |
| |
| VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); |
| pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| pipe.gp_ci_.stageCount = pipe.shader_stages_.size(); |
| pipe.gp_ci_.pStages = pipe.shader_stages_.data(); |
| pipe.CreateGraphicsPipeline(false); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 1; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {1, 2, 3}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkDrawIndexedIndirectCommand-robustBufferAccess2-08798", |
| "Index 4 is not within the bound index buffer."); |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, NoMappings) { |
| TEST_DESCRIPTION("Validate illegal index buffer values with no VkShaderDescriptorSetAndBindingMappingInfoEXT provided"); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitRenderTarget(); |
| |
| const char* vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| void main() { |
| gl_Position = vec4(pos, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); |
| pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX}; |
| VkVertexInputAttributeDescription input_attrib = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib; |
| pipe.vi_ci_.vertexAttributeDescriptionCount = 1; |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.stageCount = pipe.shader_stages_.size(); |
| pipe.gp_ci_.pStages = pipe.shader_stages_.data(); |
| pipe.CreateGraphicsPipeline(false); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 0; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42}); |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, NoHeapBound) { |
| TEST_DESCRIPTION("Validate illegal index buffer values when no descriptor heap is bound"); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitRenderTarget(); |
| |
| const char* vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| void main() { |
| gl_Position = vec4(pos, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); |
| pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX}; |
| VkVertexInputAttributeDescription input_attrib = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib; |
| pipe.vi_ci_.vertexAttributeDescriptionCount = 1; |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.stageCount = pipe.shader_stages_.size(); |
| pipe.gp_ci_.pStages = pipe.shader_stages_.data(); |
| pipe.CreateGraphicsPipeline(false); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 0; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42}); |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HeapBoundBeforePipeline) { |
| TEST_DESCRIPTION("Validate illegal index buffer values when descriptor heap is bound before the pipeline"); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitRenderTarget(); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize * 4u); |
| |
| const char* vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| void main() { |
| gl_Position = vec4(pos, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); |
| pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX}; |
| VkVertexInputAttributeDescription input_attrib = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib; |
| pipe.vi_ci_.vertexAttributeDescriptionCount = 1; |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.stageCount = pipe.shader_stages_.size(); |
| pipe.gp_ci_.pStages = pipe.shader_stages_.data(); |
| pipe.CreateGraphicsPipeline(false); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 0; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42}); |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HeapBoundAfterPipeline) { |
| TEST_DESCRIPTION("Validate illegal index buffer values when descriptor heap is bound after pipeline"); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitRenderTarget(); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize * 4u); |
| |
| const char* vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| void main() { |
| gl_Position = vec4(pos, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); |
| pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX}; |
| VkVertexInputAttributeDescription input_attrib = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib; |
| pipe.vi_ci_.vertexAttributeDescriptionCount = 1; |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.stageCount = pipe.shader_stages_.size(); |
| pipe.gp_ci_.pStages = pipe.shader_stages_.data(); |
| pipe.CreateGraphicsPipeline(false); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 0; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42}); |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, SamplerHeapBound) { |
| TEST_DESCRIPTION("Validate illegal index buffer values when sampler heap is bound"); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitRenderTarget(); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateSamplerHeap(heap_props.samplerDescriptorSize * 4u); |
| |
| const char* vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| void main() { |
| gl_Position = vec4(pos, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); |
| pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX}; |
| VkVertexInputAttributeDescription input_attrib = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib; |
| pipe.vi_ci_.vertexAttributeDescriptionCount = 1; |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.stageCount = pipe.shader_stages_.size(); |
| pipe.gp_ci_.pStages = pipe.shader_stages_.data(); |
| pipe.CreateGraphicsPipeline(false); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 0; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42}); |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, MappingsUsed) { |
| TEST_DESCRIPTION("Validate illegal index buffer values when custom mappings are used"); |
| AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitRenderTarget(); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize * 4u); |
| |
| vkt::Buffer buffer1(*m_device, 256u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer buffer2(*m_device, 256u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer buffer3(*m_device, 256u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| VkDeviceSize offset1 = desc_heap.WriteBufferDescriptor(buffer1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| VkDeviceSize offset2 = desc_heap.WriteBufferDescriptor(buffer2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| VkDeviceSize offset3 = desc_heap.WriteBufferDescriptor(buffer3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| const char* vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| layout(set=0, binding=0) buffer Buf1 { uint data1[]; } buf1; |
| layout(set=0, binding=1) readonly buffer Buf2 { uint data2[]; } buf2; |
| layout(set=1, binding=2) buffer Buf3 { uint data3[]; } buf3; |
| void main() { |
| buf3.data3[gl_VertexIndex] = buf1.data1[gl_VertexIndex] + buf2.data2[gl_VertexIndex]; |
| gl_Position = vec4(pos, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); |
| pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[3]; |
| mappings[0] = MakeSetAndBindingMapping(0u, 0u, 1u, VK_SPIRV_RESOURCE_TYPE_READ_WRITE_STORAGE_BUFFER_BIT_EXT); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[0].sourceData.constantOffset.heapOffset = static_cast<uint32_t>(offset1); |
| mappings[1] = MakeSetAndBindingMapping(0u, 1u, 1u, VK_SPIRV_RESOURCE_TYPE_READ_ONLY_STORAGE_BUFFER_BIT_EXT); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[1].sourceData.constantOffset.heapOffset = static_cast<uint32_t>(offset2); |
| mappings[2] = MakeSetAndBindingMapping(1u, 2u, 1u, VK_SPIRV_RESOURCE_TYPE_READ_WRITE_STORAGE_BUFFER_BIT_EXT); |
| mappings[2].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[2].sourceData.constantOffset.heapOffset = static_cast<uint32_t>(offset3); |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 3u; |
| mapping_info.pMappings = mappings; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX}; |
| VkVertexInputAttributeDescription input_attrib = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib; |
| pipe.vi_ci_.vertexAttributeDescriptionCount = 1; |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(&mapping_info), pipe.fs_->GetStageCreateInfo(&mapping_info)}; |
| pipe.gp_ci_.stageCount = pipe.shader_stages_.size(); |
| pipe.gp_ci_.pStages = pipe.shader_stages_.data(); |
| pipe.CreateGraphicsPipeline(false); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 0; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42}); |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12657 |
| TEST_F(NegativeGpuAVDescriptorHeap, DISABLED_DispatchWorkgroupSize) { |
| TEST_DESCRIPTION("GPU validation: Validate VkDispatchIndirectCommand with descriptor heap"); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorHeap); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| |
| PFN_vkSetPhysicalDeviceLimitsEXT fpvkSetPhysicalDeviceLimitsEXT = nullptr; |
| PFN_vkGetOriginalPhysicalDeviceLimitsEXT fpvkGetOriginalPhysicalDeviceLimitsEXT = nullptr; |
| if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceLimitsEXT, fpvkGetOriginalPhysicalDeviceLimitsEXT)) { |
| GTEST_SKIP() << "Failed to load device profile layer."; |
| } |
| |
| VkPhysicalDeviceProperties props; |
| fpvkGetOriginalPhysicalDeviceLimitsEXT(Gpu(), &props.limits); |
| props.limits.maxComputeWorkGroupCount[0] = 2; |
| props.limits.maxComputeWorkGroupCount[1] = 2; |
| props.limits.maxComputeWorkGroupCount[2] = 2; |
| fpvkSetPhysicalDeviceLimitsEXT(Gpu(), &props.limits); |
| |
| RETURN_IF_SKIP(InitState()); |
| GetPhysicalDeviceProperties2(heap_props); |
| |
| vkt::Buffer indirect_buffer(*m_device, 5 * sizeof(VkDispatchIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, |
| kHostVisibleMemProps); |
| VkDispatchIndirectCommand* ptr = static_cast<VkDispatchIndirectCommand*>(indirect_buffer.Memory().Map()); |
| // VkDispatchIndirectCommand[0] |
| ptr->x = 4; // over |
| ptr->y = 2; |
| ptr->z = 1; |
| // VkDispatchIndirectCommand[1] |
| ptr++; |
| ptr->x = 2; |
| ptr->y = 3; // over |
| ptr->z = 1; |
| // VkDispatchIndirectCommand[2] - valid in between |
| ptr++; |
| ptr->x = 1; |
| ptr->y = 1; |
| ptr->z = 1; |
| // VkDispatchIndirectCommand[3] |
| ptr++; |
| ptr->x = 0; // allowed |
| ptr->y = 2; |
| ptr->z = 3; // over |
| // VkDispatchIndirectCommand[4] |
| ptr++; |
| ptr->x = 3; // over |
| ptr->y = 2; |
| ptr->z = 3; // over |
| |
| vkt::HeapComputePipeline pipe(*m_device, kMinimalShaderGlsl, SPV_ENV_VULKAN_1_0); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkDispatchIndirectCommand-x-00417"); |
| vk::CmdDispatchIndirect(m_command_buffer, indirect_buffer, 0); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkDispatchIndirectCommand-y-00418"); |
| vk::CmdDispatchIndirect(m_command_buffer, indirect_buffer, sizeof(VkDispatchIndirectCommand)); |
| |
| // valid |
| vk::CmdDispatchIndirect(m_command_buffer, indirect_buffer, 2 * sizeof(VkDispatchIndirectCommand)); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkDispatchIndirectCommand-z-00419"); |
| vk::CmdDispatchIndirect(m_command_buffer, indirect_buffer, 3 * sizeof(VkDispatchIndirectCommand)); |
| |
| // Only expect to have the first error return |
| m_errorMonitor->SetDesiredError("VUID-VkDispatchIndirectCommand-x-00417"); |
| vk::CmdDispatchIndirect(m_command_buffer, indirect_buffer, 4 * sizeof(VkDispatchIndirectCommand)); |
| |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Check again in a 2nd submitted command buffer |
| m_command_buffer.Reset(); |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkDispatchIndirectCommand-x-00417"); |
| vk::CmdDispatchIndirect(m_command_buffer, indirect_buffer, 0); |
| |
| vk::CmdDispatchIndirect(m_command_buffer, indirect_buffer, 2 * sizeof(VkDispatchIndirectCommand)); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkDispatchIndirectCommand-x-00417"); |
| vk::CmdDispatchIndirect(m_command_buffer, indirect_buffer, 0); |
| |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HeapRebound) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitRenderTarget(); |
| |
| const VkDeviceSize app_size = heap_props.bufferDescriptorAlignment * 4u; |
| vkt::DescriptorHeap desc_heap1(*this); |
| vkt::DescriptorHeap desc_heap2(*this); |
| desc_heap1.CreateResourceHeap(app_size); |
| desc_heap2.CreateResourceHeap(app_size); |
| |
| const char* vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| void main() { |
| gl_Position = vec4(pos, 1.0); |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); |
| pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| |
| VkVertexInputBindingDescription input_binding = {0, 3 * sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX}; |
| VkVertexInputAttributeDescription input_attrib = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; |
| pipe.vi_ci_.pVertexBindingDescriptions = &input_binding; |
| pipe.vi_ci_.vertexBindingDescriptionCount = 1; |
| pipe.vi_ci_.pVertexAttributeDescriptions = &input_attrib; |
| pipe.vi_ci_.vertexAttributeDescriptionCount = 1; |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.stageCount = pipe.shader_stages_.size(); |
| pipe.gp_ci_.pStages = pipe.shader_stages_.data(); |
| pipe.CreateGraphicsPipeline(false); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 0; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| |
| desc_heap1.BindResourceHeap(m_command_buffer); |
| |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42}); |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| desc_heap2.BindResourceHeap(m_command_buffer); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ShaderObjects) { |
| TEST_DESCRIPTION("Validate illegal index buffer values with shader objects"); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitDynamicRenderTarget(); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize * 4u); |
| |
| const char* vsSource = R"glsl( |
| #version 450 |
| layout(location=0) in vec3 pos; |
| void main() { |
| gl_Position = vec4(pos, 1.0); |
| } |
| )glsl"; |
| |
| const auto vspv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vsSource); |
| VkShaderCreateInfoEXT vert_ci = ShaderCreateInfoHeap(vspv, VK_SHADER_STAGE_VERTEX_BIT); |
| const vkt::Shader vert_shader(*m_device, vert_ci); |
| |
| const auto fspv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| VkShaderCreateInfoEXT frag_ci = ShaderCreateInfoHeap(fspv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| const vkt::Shader frag_shader(*m_device, frag_ci); |
| |
| VkDrawIndexedIndirectCommand draw_params{}; |
| draw_params.indexCount = 3; |
| draw_params.instanceCount = 1; |
| draw_params.firstIndex = 0; |
| draw_params.vertexOffset = 0; |
| draw_params.firstInstance = 0; |
| vkt::Buffer draw_params_buffer = vkt::IndirectBuffer<VkDrawIndexedIndirectCommand>(*m_device, {draw_params}); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| VkShaderStageFlagBits stages[2] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT}; |
| VkShaderEXT shaders[2] = {vert_shader.handle(), frag_shader.handle()}; |
| vk::CmdBindShadersEXT(m_command_buffer, 2, stages, shaders); |
| |
| vk::CmdSetRasterizerDiscardEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetCullModeEXT(m_command_buffer, VK_CULL_MODE_NONE); |
| vk::CmdSetDepthTestEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetStencilTestEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetPolygonModeEXT(m_command_buffer, VK_POLYGON_MODE_FILL); |
| vk::CmdSetPrimitiveTopology(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); |
| vk::CmdSetPrimitiveRestartEnableEXT(m_command_buffer, VK_FALSE); |
| VkColorBlendEquationEXT colorBlendEquation = { |
| VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE, VK_BLEND_OP_ADD, |
| }; |
| vk::CmdSetColorBlendEquationEXT(m_command_buffer, 0, 1u, &colorBlendEquation); |
| VkViewport viewport = {0.0f, 0.0f, 32.0f, 32.0f, 0.0f, 1.0f}; |
| vk::CmdSetViewportWithCountEXT(m_command_buffer, 1, &viewport); |
| VkRect2D scissor = {{0, 0}, {32, 32}}; |
| vk::CmdSetScissorWithCountEXT(m_command_buffer, 1, &scissor); |
| vk::CmdSetDepthBiasEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetRasterizationSamplesEXT(m_command_buffer, VK_SAMPLE_COUNT_1_BIT); |
| VkSampleMask sampleMask = 0xFFFFFFFF; |
| vk::CmdSetSampleMaskEXT(m_command_buffer, VK_SAMPLE_COUNT_1_BIT, &sampleMask); |
| vk::CmdSetAlphaToCoverageEnableEXT(m_command_buffer, VK_FALSE); |
| VkBool32 colorBlendEnable = VK_FALSE; |
| vk::CmdSetColorBlendEnableEXT(m_command_buffer, 0u, 1u, &colorBlendEnable); |
| VkColorComponentFlags colorWriteMask = |
| VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
| vk::CmdSetColorWriteMaskEXT(m_command_buffer, 0u, 1u, &colorWriteMask); |
| |
| VkVertexInputBindingDescription2EXT binding = vku::InitStructHelper(); |
| binding.binding = 0u; |
| binding.stride = 3 * sizeof(float); |
| binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; |
| binding.divisor = 1u; |
| |
| VkVertexInputAttributeDescription2EXT attribute = vku::InitStructHelper(); |
| attribute.location = 0u; |
| attribute.binding = 0u; |
| attribute.format = VK_FORMAT_R32G32B32_SFLOAT; |
| attribute.offset = 0u; |
| vk::CmdSetVertexInputEXT(m_command_buffer, 1u, &binding, 1u, &attribute); |
| |
| vkt::Buffer index_buffer = vkt::IndexBuffer<uint32_t>(*m_device, {0, 666, 42}); |
| vkt::Buffer vertex_buffer = vkt::VertexBuffer<float>(*m_device, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}); |
| VkDeviceSize vertex_buffer_offset = 0; |
| vk::CmdBindIndexBuffer(m_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vertex_buffer.handle(), &vertex_buffer_offset); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 666"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDrawIndexedIndirect-None-02721", "Vertex index 42"); |
| vk::CmdDrawIndexedIndirect(m_command_buffer, draw_params_buffer, 0, 1, sizeof(VkDrawIndexedIndirectCommand)); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBConstantOffset) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(1, 3); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| // 1 resource stride OOB |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)desc_heap.resource_heap_.CreateInfo().size; |
| mapping.sourceData.constantOffset.heapArrayStride = 0; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(local_size_x = 1) in; |
| layout(set = 1, binding = 3) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBConstantOffsetDynamicIndex) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| auto ssbo_memory = (uint32_t*)ssbo_buffer.Memory().Map(); |
| ssbo_memory[0] = 3; |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 1); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mapping.sourceData.constantOffset.heapArrayStride = (uint32_t)resource_stride; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(local_size_x = 1) in; |
| // only [0] is valid, [1] is uninitialized, [2] will go OOB |
| layout(set = 0, binding = 1) buffer A { uint index; uint result; } ssbo[4]; |
| void main() { |
| uint index = ssbo[0].index; |
| ssbo[index].result = 99; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBMultipleBinding) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| // Goal is to mix-match the set/binding and mapping index |
| uint32_t oob_offset = (uint32_t)(heap_props.minResourceHeapReservedRange + resource_stride); |
| VkDescriptorSetAndBindingMappingEXT mappings[4]; |
| mappings[0] = MakeSetAndBindingMapping(1, 2); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[0].sourceData.constantOffset.heapOffset = oob_offset; |
| mappings[0].sourceData.constantOffset.heapArrayStride = 0; |
| // This mapping is valid |
| mappings[1] = MakeSetAndBindingMapping(0, 2); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[1].sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[1].sourceData.constantOffset.heapArrayStride = 0; |
| mappings[2] = MakeSetAndBindingMapping(1, 0); |
| mappings[2].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[2].sourceData.constantOffset.heapOffset = oob_offset + (uint32_t)resource_stride; |
| mappings[2].sourceData.constantOffset.heapArrayStride = 0; |
| mappings[3] = MakeSetAndBindingMapping(0, 1); |
| mappings[3].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[3].sourceData.constantOffset.heapOffset = oob_offset; |
| mappings[3].sourceData.constantOffset.heapArrayStride = 0; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 4; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(local_size_x = 1) in; |
| layout(set = 0, binding = 1) buffer A { uint a; }; |
| layout(set = 0, binding = 2) buffer B { uint b; }; |
| layout(set = 1, binding = 0) buffer C { uint c; }; |
| layout(set = 1, binding = 2) buffer D { uint d; }; |
| void main() { |
| a = 1; |
| b = 2; // valid |
| c = 3; |
| d = 4; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBPushIndex) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| mapping.sourceData.pushIndex.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mapping.sourceData.pushIndex.heapArrayStride = 0; |
| mapping.sourceData.pushIndex.pushOffset = 8; |
| mapping.sourceData.pushIndex.heapIndexStride = 2; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(local_size_x = 1) in; |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| |
| uint32_t push_index = 512; |
| m_command_buffer.PushData(8, sizeof(uint32_t), &push_index); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBIndirectIndex) { |
| TEST_DESCRIPTION("Also tests having different bindings and calling things twice"); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 4, true); |
| |
| vkt::Buffer indirect_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[3]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mappings[0].sourceData.indirectIndex.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[0].sourceData.indirectIndex.pushOffset = 16; |
| mappings[0].sourceData.indirectIndex.addressOffset = 4; |
| mappings[0].sourceData.indirectIndex.heapIndexStride = 1; |
| mappings[0].sourceData.indirectIndex.heapArrayStride = (uint32_t)resource_stride; |
| mappings[1] = MakeSetAndBindingMapping(0, 2); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_DATA_EXT; |
| mappings[1].sourceData.pushDataOffset = 0; |
| mappings[2] = MakeSetAndBindingMapping(0, 1); |
| mappings[2].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_ARRAY_EXT; |
| mappings[2].sourceData.indirectIndexArray.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[2].sourceData.indirectIndexArray.pushOffset = 16; |
| mappings[2].sourceData.indirectIndexArray.addressOffset = 4; |
| mappings[2].sourceData.indirectIndexArray.heapIndexStride = 1; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 3; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(local_size_x = 1) in; |
| // x[3] and y[3] is where it goes OOB |
| layout(set = 0, binding = 0) buffer A { uint a; } x[4]; |
| layout(set = 0, binding = 1) buffer B { uint b; } y[4]; |
| layout(set = 0, binding = 2) uniform C { uint a_index; uint b_index; }; |
| void main() { |
| x[a_index].a = 1; |
| y[b_index].b = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| uint32_t* indirect_data = (uint32_t*)indirect_buffer.Memory().Map(); |
| for (uint32_t i = 0; i < 8; i++) { |
| indirect_data[i] = (uint32_t)resource_stride * i; |
| } |
| |
| VkDeviceAddress indirect_address = indirect_buffer.Address(); |
| m_command_buffer.PushData(16, sizeof(VkDeviceAddress), &indirect_address); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| // first pass good |
| uint32_t a_index = 0; |
| uint32_t b_index = 0; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &a_index); |
| m_command_buffer.PushData(4, sizeof(uint32_t), &b_index); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| // second pass |
| a_index = 3; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &a_index); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| // third pass |
| a_index = 0; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &a_index); |
| b_index = 3; |
| m_command_buffer.PushData(4, sizeof(uint32_t), &b_index); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| // one for each indirect mapping |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBShaderObjects) { |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::fragmentStoresAndAtomics); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| InitDynamicRenderTarget(); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize * 2, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = |
| (uint32_t)(heap_props.minResourceHeapReservedRange + heap_props.bufferDescriptorSize); |
| mapping.sourceData.constantOffset.heapArrayStride = (uint32_t)heap_props.bufferDescriptorSize; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| const char* fs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { vec4 a; } x[4]; |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = x[1].a; |
| } |
| )glsl"; |
| |
| const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexDrawPassthroughGlsl); |
| VkShaderCreateInfoEXT vert_shader_ci = ShaderCreateInfoHeap(vert_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| const vkt::Shader vert_shader(*m_device, vert_shader_ci); |
| |
| const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, fs_source); |
| VkShaderCreateInfoEXT frag_shader_ci = ShaderCreateInfoHeap(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT, &mapping_info); |
| const vkt::Shader frag_shader(*m_device, frag_shader_ci); |
| |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| m_command_buffer.Begin(&begin_info); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| VkShaderStageFlagBits stages[2] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT}; |
| VkShaderEXT shaders[2] = {vert_shader.handle(), frag_shader.handle()}; |
| vk::CmdBindShadersEXT(m_command_buffer, 2, stages, shaders); |
| |
| SetDefaultDynamicStatesExclude(); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-11309", gpuav::glsl::kMaxErrorsPerCmd); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBRebindHeap) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptorAtOffset(ssbo_buffer.AddressRange(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, |
| desc_heap.GetResourceHeapReservedRangeOffset() + resource_stride); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)(heap_props.minResourceHeapReservedRange + resource_stride); |
| mapping.sourceData.constantOffset.heapArrayStride = 0; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| desc_heap.BindResourceHeap(m_command_buffer); // normal, will bind full heap |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| // Bind 1 less resource, which causes the OOB |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| bind_resource_info.heapRange.size -= resource_stride; |
| bind_resource_info.reservedRangeOffset = desc_heap.GetResourceHeapReservedRangeOffset(); |
| bind_resource_info.reservedRangeSize = heap_props.minResourceHeapReservedRange; |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); // back to full heap |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBSecondaryInheritance) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)(heap_props.minResourceHeapReservedRange + resource_stride); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| VkBindHeapInfoEXT resource_bind_info = vku::InitStructHelper(); |
| resource_bind_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| resource_bind_info.reservedRangeOffset = desc_heap.GetResourceHeapReservedRangeOffset(); |
| resource_bind_info.reservedRangeSize = heap_props.minResourceHeapReservedRange; |
| VkCommandBufferInheritanceDescriptorHeapInfoEXT inh_desc_heap_info = vku::InitStructHelper(); |
| inh_desc_heap_info.pResourceHeapBindInfo = &resource_bind_info; |
| VkCommandBufferInheritanceInfo inh = vku::InitStructHelper(&inh_desc_heap_info); |
| VkCommandBufferBeginInfo cbbi = vku::InitStructHelper(); |
| cbbi.pInheritanceInfo = &inh; |
| |
| vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); |
| secondary.Begin(&cbbi); |
| vk::CmdBindPipeline(secondary, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(secondary, 1u, 1u, 1u); |
| secondary.End(); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdExecuteCommands(m_command_buffer, 1, &secondary.handle()); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBSecondaryBind) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)(heap_props.minResourceHeapReservedRange + resource_stride); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| VkBindHeapInfoEXT resource_bind_info = vku::InitStructHelper(); |
| resource_bind_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| resource_bind_info.reservedRangeOffset = desc_heap.GetResourceHeapReservedRangeOffset(); |
| resource_bind_info.reservedRangeSize = heap_props.minResourceHeapReservedRange; |
| |
| // No VkCommandBufferInheritanceDescriptorHeapInfoEXT |
| vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); |
| secondary.Begin(); |
| vk::CmdBindResourceHeapEXT(secondary, &resource_bind_info); |
| vk::CmdBindPipeline(secondary, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(secondary, 1u, 1u, 1u); |
| secondary.End(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdExecuteCommands(m_command_buffer, 1, &secondary.handle()); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, SamplerOOB) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| const VkDeviceSize sampler_stride = heap_props.samplerDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| desc_heap.CreateSamplerHeap(sampler_stride, true); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| const VkDeviceSize image_offset = desc_heap.WriteImageDescriptor(image); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| VkHostAddressRangeEXT sampler_host = {desc_heap.sampler_heap_data_, static_cast<size_t>(sampler_stride)}; |
| vk::WriteSamplerDescriptorsEXT(*m_device, 1u, &sampler_info, &sampler_host); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[0].sourceData.constantOffset.heapOffset = (uint32_t)(image_offset + resource_stride); |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[1].sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minSamplerHeapReservedRange; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D kTextures2D; |
| layout(set = 0, binding = 1) uniform sampler kSampler; |
| |
| void main() { |
| vec4 out_color = texture(sampler2D(kTextures2D, kSampler), vec2(0)); |
| } |
| )glsl"; |
| // bad image mappings |
| vkt::HeapComputePipeline pipe_image(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| mappings[0].sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[1].sourceData.constantOffset.heapOffset = (uint32_t)(heap_props.minSamplerHeapReservedRange + sampler_stride); |
| // bad sampler mappings |
| vkt::HeapComputePipeline pipe_sampler(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe_image); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe_sampler); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, SamplerOOBCombinedImageSampler) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| const VkDeviceSize sampler_stride = heap_props.samplerDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| desc_heap.CreateSamplerHeap(sampler_stride, true); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| desc_heap.WriteImageDescriptor(image, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| desc_heap.WriteSamplerDescriptor(&sampler_info); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)(heap_props.minResourceHeapReservedRange + resource_stride); |
| mapping.sourceData.constantOffset.heapArrayStride = 0; |
| mapping.sourceData.constantOffset.samplerHeapOffset = (uint32_t)heap_props.minSamplerHeapReservedRange; |
| mapping.sourceData.constantOffset.samplerHeapArrayStride = 0; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform sampler2D tex; |
| |
| void main() { |
| vec4 out_color = texture(tex, vec2(0.5f)); |
| } |
| )glsl"; |
| // bad image mappings |
| vkt::HeapComputePipeline pipe_image(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mapping.sourceData.constantOffset.samplerHeapOffset = (uint32_t)(heap_props.minSamplerHeapReservedRange + sampler_stride); |
| // bad sampler mappings |
| vkt::HeapComputePipeline pipe_sampler(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe_image); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe_sampler); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBStorageImage) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT); |
| desc_heap.WriteImageDescriptor(image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0, 2); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mapping.sourceData.constantOffset.heapArrayStride = (uint32_t)resource_stride; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0, r32ui) uniform uimage2D good_si; |
| layout(set = 0, binding = 1, r32ui) uniform uimage2D bad_si; |
| void main() { |
| uvec4 texel = imageLoad(bad_si, ivec2(0, 0)); |
| imageStore(good_si, ivec2(1, 1), texel * 2); |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| // VUID-vkCmdDispatch-None-11309 |
| m_errorMonitor->SetDesiredError("bad_si"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersBuffer) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if ((heap_props.minResourceHeapReservedRange / heap_props.bufferDescriptorSize) >= 10000) { |
| GTEST_SKIP() << "reserved range is too large, access will not be OOB"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_descriptor_heap : require |
| layout (descriptor_heap) buffer SSBO_0 { |
| uint data; |
| } heapBuffer[]; |
| |
| void main() { |
| // Something large enough to get pass the reserved range |
| heapBuffer[10000].data = 0; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersBufferOldGlsl) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if ((heap_props.minResourceHeapReservedRange / heap_props.bufferDescriptorSize) >= 10000) { |
| GTEST_SKIP() << "reserved range is too large, access will not be OOB"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| |
| // Same shader above in ResourceOOBUntypedPointers, but using the old (still valid) GLSL output |
| const char* cs_source = R"asm( |
| OpCapability Shader |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpMemberName %SSBO_0 0 "data" |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorate %SSBO_0 Block |
| OpMemberDecorate %SSBO_0 0 Offset 0 |
| OpDecorateId %_runtimearr_16 ArrayStrideIdEXT %17 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %int = OpTypeInt 32 1 |
| %int_10000 = OpConstant %int 10000 |
| %uint = OpTypeInt 32 0 |
| %SSBO_0 = OpTypeStruct %uint |
| %int_0 = OpConstant %int 0 |
| %uint_0 = OpConstant %uint 0 |
| %_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer |
| %16 = OpTypeBufferEXT StorageBuffer |
| %17 = OpConstantSizeOfEXT %int %16 |
| %_runtimearr_16 = OpTypeRuntimeArray %16 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %15 = OpUntypedAccessChainKHR %_ptr_UniformConstant %_runtimearr_16 %resource_heap %int_10000 |
| %19 = OpBufferPointerEXT %_ptr_StorageBuffer %15 |
| %20 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO_0 %19 %int_0 |
| OpStore %20 %uint_0 |
| OpReturn |
| OpFunctionEnd |
| )asm"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersBufferAtomics) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if ((heap_props.minResourceHeapReservedRange / heap_props.bufferDescriptorSize) >= 10000) { |
| GTEST_SKIP() << "reserved range is too large, access will not be OOB"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_descriptor_heap : enable |
| #extension GL_KHR_memory_scope_semantics : enable |
| |
| layout (descriptor_heap) buffer heap { |
| uint a; |
| } heapBuffer[]; |
| |
| void main() { |
| atomicStore(heapBuffer[10000].a, 0u, gl_ScopeDevice, 0, 0); |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersStorageImage) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if ((heap_props.minResourceHeapReservedRange / heap_props.imageDescriptorSize) >= 10000) { |
| GTEST_SKIP() << "reserved range is too large, access will not be OOB"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 256, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| // Note - this looks the same in the "old" glslang code as well |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_descriptor_heap : require |
| layout(descriptor_heap, rgba8i) uniform iimage2D heapImages[]; |
| layout(set = 0, binding = 0) buffer SSBO { ivec4 result; }; |
| void main() { |
| ivec4 data = imageLoad(heapImages[10000], ivec2(0)); |
| result = data; |
| } |
| )glsl"; |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersSampledImage) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if ((heap_props.minResourceHeapReservedRange / heap_props.imageDescriptorSize) >= 10000) { |
| GTEST_SKIP() << "reserved range is too large, access will not be OOB"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| desc_heap.CreateSamplerHeap(heap_props.samplerDescriptorSize); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 256, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| // Note - this looks the same in the "old" glslang code as well |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_descriptor_heap : require |
| layout(descriptor_heap) uniform texture2D heapTextures[]; |
| layout(descriptor_heap) uniform sampler heapSamplers[]; |
| layout(set = 0, binding = 0) buffer SSBO { vec4 result; }; |
| void main() { |
| vec4 data = texture(sampler2D(heapTextures[10000], heapSamplers[0]), vec2(0.5f)); |
| result = data; |
| } |
| )glsl"; |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, SamplerOOBUntypedPointers) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if ((heap_props.minSamplerHeapReservedRange / heap_props.samplerDescriptorSize) >= 10000) { |
| GTEST_SKIP() << "reserved range is too large, access will not be OOB"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.imageDescriptorSize); |
| desc_heap.CreateSamplerHeap(heap_props.samplerDescriptorSize); |
| |
| // Note - this looks the same in the "old" glslang code as well |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_descriptor_heap : require |
| layout(descriptor_heap) uniform texture2D heapTextures[]; |
| layout(descriptor_heap) uniform sampler heapSamplers[]; |
| void main() { |
| vec4 data = texture(sampler2D(heapTextures[0], heapSamplers[10000]), vec2(0.5f)); |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersOffsetId) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize * 2); |
| |
| vkt::Buffer buffer_0(*m_device, 64, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(buffer_0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| // layout(storage_buffer) SSBO { |
| // uint a; |
| // }; |
| // layout(offset = buffer_size * 10000) heap { |
| // SSBO runtime_buffer[]; |
| // } heap_layout; |
| // |
| // heap_layout.runtime_buffer[0].a = 42; |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorate %SSBO Block |
| OpMemberDecorate %SSBO 0 Offset 0 |
| OpDecorate %heap_layout Block |
| OpMemberDecorateIdEXT %heap_layout 0 OffsetIdEXT %crazy_offset |
| OpDecorateId %runtime_buffer ArrayStrideIdEXT %buf_size |
| %void = OpTypeVoid |
| %void_fn = OpTypeFunction %void |
| %int = OpTypeInt 32 1 |
| %uint = OpTypeInt 32 0 |
| %int_0 = OpConstant %int 0 |
| %uint_42 = OpConstant %uint 42 |
| %int_10k = OpConstant %int 10000 |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %SSBO = OpTypeStruct %uint |
| %_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer |
| |
| %type_buffer = OpTypeBufferEXT StorageBuffer |
| %buf_size = OpConstantSizeOfEXT %int %type_buffer |
| %crazy_offset = OpSpecConstantOp %int IMul %buf_size %int_10k |
| %runtime_buffer = OpTypeRuntimeArray %type_buffer |
| |
| %heap_layout = OpTypeStruct %runtime_buffer |
| |
| %main = OpFunction %void None %void_fn |
| %5 = OpLabel |
| |
| %heap_index_0 = OpUntypedAccessChainKHR %_ptr_UniformConstant %heap_layout %resource_heap %int_0 %int_0 |
| %buf_ptr_0 = OpBufferPointerEXT %_ptr_StorageBuffer %heap_index_0 |
| %member_0 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO %buf_ptr_0 %int_0 |
| OpStore %member_0 %uint_42 |
| |
| OpReturn |
| OpFunctionEnd |
| )"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, UntypedPointersOffsetIdNonArray) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if ((heap_props.minResourceHeapReservedRange / heap_props.imageDescriptorSize) >= 10000) { |
| GTEST_SKIP() << "reserved range is too large, access will not be OOB"; |
| } |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 3); |
| |
| vkt::Buffer buffer_0(*m_device, 64, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); |
| vkt::Buffer buffer_1(*m_device, 64, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); |
| desc_heap.WriteBufferDescriptorAtOffset(buffer_0.AddressRange(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, resource_stride * 2); |
| desc_heap.WriteBufferDescriptorAtOffset(buffer_1.AddressRange(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, resource_stride * 1); |
| |
| // layout(storage_buffer) SSBO { |
| // uint data; |
| // }; |
| // heap { |
| // layout(offset = buffer_size * 2) SSBO buffer_0; |
| // layout(offset = buffer_size * 10000) SSBO buffer_1; |
| // } heap_layout; |
| // |
| // heap_layout.buffer_0.data = 42; |
| // heap_layout.buffer_1.data = 43; |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorate %SSBO Block |
| OpMemberDecorate %SSBO 0 Offset 0 |
| OpDecorate %heap_layout Block |
| OpMemberDecorateIdEXT %heap_layout 0 OffsetIdEXT %buf_size2 |
| OpMemberDecorateIdEXT %heap_layout 1 OffsetIdEXT %bad_offset |
| %void = OpTypeVoid |
| %void_fn = OpTypeFunction %void |
| %int = OpTypeInt 32 1 |
| %uint = OpTypeInt 32 0 |
| %int_0 = OpConstant %int 0 |
| %int_1 = OpConstant %int 1 |
| %int_2 = OpConstant %int 2 |
| %uint_42 = OpConstant %uint 42 |
| %uint_43 = OpConstant %uint 43 |
| %int_10k = OpConstant %int 10000 |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %SSBO = OpTypeStruct %uint |
| %_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer |
| |
| %type_buffer = OpTypeBufferEXT StorageBuffer |
| %buf_size = OpConstantSizeOfEXT %int %type_buffer |
| %buf_size2 = OpSpecConstantOp %int IMul %buf_size %int_2 |
| %buf_size_again = OpSpecConstantOp %int ISub %buf_size2 %buf_size |
| %bad_offset = OpSpecConstantOp %int IMul %buf_size_again %int_10k |
| |
| %heap_layout = OpTypeStruct %type_buffer %type_buffer |
| |
| %main = OpFunction %void None %void_fn |
| %5 = OpLabel |
| |
| %heap_index_0 = OpUntypedAccessChainKHR %_ptr_UniformConstant %heap_layout %resource_heap |
| %buf_ptr_0 = OpBufferPointerEXT %_ptr_StorageBuffer %heap_index_0 |
| %member_0 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO %buf_ptr_0 %int_0 |
| OpStore %member_0 %uint_42 |
| |
| %heap_index_1 = OpUntypedAccessChainKHR %_ptr_UniformConstant %heap_layout %resource_heap %int_1 |
| %buf_ptr_1 = OpBufferPointerEXT %_ptr_StorageBuffer %heap_index_1 |
| %member_1 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO %buf_ptr_1 %int_0 |
| OpStore %member_1 %uint_43 |
| |
| OpReturn |
| OpFunctionEnd |
| )"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, BufferDescriptorAlignmentMapping) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| // [SSBO, SSBO, UBO, UBO] |
| desc_heap.CreateResourceHeap(resource_stride * 4); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| vkt::Buffer ubo_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ubo_buffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| desc_heap.WriteBufferDescriptor(ubo_buffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| |
| const uint32_t push_data = (uint32_t)resource_stride; |
| const uint32_t bad_push_data = (uint32_t)resource_stride + 1u; |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| mappings[0].sourceData.pushIndex.heapOffset = 0; |
| mappings[0].sourceData.pushIndex.heapIndexStride = 1; |
| mappings[0].sourceData.pushIndex.pushOffset = 0; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| mappings[1].sourceData.pushIndex.heapOffset = (uint32_t)resource_stride; |
| mappings[1].sourceData.pushIndex.heapIndexStride = 1; |
| mappings[1].sourceData.pushIndex.pushOffset = 4; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer SSBO { uint a; }; |
| layout(set = 0, binding = 1) uniform UBO { uint b; }; |
| void main() { |
| a = b; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| // bad SSBO |
| m_command_buffer.PushData(0, sizeof(uint32_t), &bad_push_data); |
| m_command_buffer.PushData(4, sizeof(uint32_t), &push_data); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| // bad UBO |
| m_command_buffer.PushData(0, sizeof(uint32_t), &push_data); |
| m_command_buffer.PushData(4, sizeof(uint32_t), &bad_push_data); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11297", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ImageSamplerDescriptorAlignment) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| const VkDeviceSize sampler_stride = heap_props.samplerDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| desc_heap.CreateSamplerHeap(sampler_stride * 2); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| desc_heap.WriteImageDescriptor(image, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| desc_heap.WriteSamplerDescriptor(&sampler_info); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mappings[0].sourceData.indirectIndex.pushOffset = 0; |
| mappings[0].sourceData.indirectIndex.heapIndexStride = 1; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mappings[1].sourceData.indirectIndex.pushOffset = 8; |
| mappings[1].sourceData.indirectIndex.heapIndexStride = 1; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D kTextures2D; |
| layout(set = 0, binding = 1) uniform sampler kSampler; |
| |
| void main() { |
| vec4 out_color = texture(sampler2D(kTextures2D, kSampler), vec2(0)); |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| vkt::Buffer indirect_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| uint32_t* indirect_data = (uint32_t*)indirect_buffer.Memory().Map(); |
| indirect_data[0] = 0; // valid |
| indirect_data[1] = 1; // invalid |
| VkDeviceAddress indirect_address = indirect_buffer.Address(); |
| VkDeviceAddress bad_indirect_address = indirect_address + 4; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &bad_indirect_address); |
| m_command_buffer.PushData(8, sizeof(VkDeviceAddress), &indirect_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address); |
| m_command_buffer.PushData(8, sizeof(VkDeviceAddress), &bad_indirect_address); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11298"); // image |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11299"); // sampler |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, BufferDescriptorAlignmentUntypedPointers) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| |
| vkt::Buffer buffer_0(*m_device, 64, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(buffer_0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| desc_heap.WriteBufferDescriptor(buffer_0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| // layout(storage_buffer) SSBO { |
| // uint a; |
| // }; |
| // layout(offset = 1) heap { |
| // SSBO runtime_buffer[]; |
| // } heap_layout; |
| // |
| // heap_layout.runtime_buffer[0].a = 42; |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorate %SSBO Block |
| OpMemberDecorate %SSBO 0 Offset 0 |
| OpDecorate %heap_layout Block |
| OpMemberDecorateIdEXT %heap_layout 0 OffsetIdEXT %uint_1 |
| OpDecorateId %runtime_buffer ArrayStrideIdEXT %buf_size |
| %void = OpTypeVoid |
| %void_fn = OpTypeFunction %void |
| %int = OpTypeInt 32 1 |
| %uint = OpTypeInt 32 0 |
| %int_0 = OpConstant %int 0 |
| %uint_1 = OpConstant %uint 1 |
| %uint_42 = OpConstant %uint 42 |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %SSBO = OpTypeStruct %uint |
| %_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer |
| |
| %type_buffer = OpTypeBufferEXT StorageBuffer |
| %buf_size = OpConstantSizeOfEXT %int %type_buffer |
| %runtime_buffer = OpTypeRuntimeArray %type_buffer |
| |
| %heap_layout = OpTypeStruct %runtime_buffer |
| |
| %main = OpFunction %void None %void_fn |
| %5 = OpLabel |
| |
| %heap_index_0 = OpUntypedAccessChainKHR %_ptr_UniformConstant %heap_layout %resource_heap %int_0 %int_0 |
| %buf_ptr_0 = OpBufferPointerEXT %_ptr_StorageBuffer %heap_index_0 |
| %member_0 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO %buf_ptr_0 %int_0 |
| OpStore %member_0 %uint_42 |
| |
| OpReturn |
| OpFunctionEnd |
| )"; |
| // spirv-val can detect this, but still want to test at GPU-AV time |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkShaderModuleCreateInfo-pCode-08737"); |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-bufferDescriptorAlignment-11384"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, StorageImageDescriptorAlignmentUntypedPointers) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8_UINT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT); |
| desc_heap.WriteImageDescriptor(image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL); |
| desc_heap.WriteImageDescriptor(image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL); |
| |
| // [stride: spec_constant_id = 1] |
| // layout(descriptor_heap, R32ui) uniform uimage2D si[]; |
| // |
| // imageStore(si[1], ivec2(1), uvec4(1)); // bad |
| // imageStore(si[0], ivec2(1), uvec4(1)); // good |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorateId %runtime_image ArrayStrideIdEXT %bad_stride |
| OpDecorate %bad_stride SpecId 1 |
| %void = OpTypeVoid |
| %4 = OpTypeFunction %void |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %int = OpTypeInt 32 1 |
| %int_1 = OpConstant %int 1 |
| %int_0 = OpConstant %int 0 |
| %uint = OpTypeInt 32 0 |
| %12 = OpTypeImage %uint 2D 0 0 0 2 R32ui |
| %bad_stride = OpSpecConstant %int 0 |
| %runtime_image = OpTypeRuntimeArray %12 |
| %v2int = OpTypeVector %int 2 |
| %18 = OpConstantComposite %v2int %int_1 %int_1 |
| %v4uint = OpTypeVector %uint 4 |
| %uint_1 = OpConstant %uint 1 |
| %21 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1 |
| %main = OpFunction %void None %4 |
| %6 = OpLabel |
| %one_ac = OpUntypedAccessChainKHR %_ptr_UniformConstant %runtime_image %resource_heap %int_1 |
| %si1_load = OpLoad %12 %one_ac |
| OpImageWrite %si1_load %18 %21 ZeroExtend |
| %zero_ac = OpUntypedAccessChainKHR %_ptr_UniformConstant %runtime_image %resource_heap |
| %si0_load = OpLoad %12 %zero_ac |
| OpImageWrite %si0_load %18 %21 ZeroExtend |
| OpReturn |
| OpFunctionEnd |
| )"; |
| const uint32_t data = (uint32_t)heap_props.imageDescriptorSize - 1; |
| const VkSpecializationMapEntry entry = {1, 0, sizeof(uint32_t)}; |
| const VkSpecializationInfo specialization_info = {1, &entry, sizeof(uint32_t), &data}; |
| // spirv-val can detect this, but still want to test at GPU-AV time |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineShaderStageCreateInfo-pSpecializationInfo-06849"); |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM, &specialization_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-imageDescriptorAlignment-11349"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, StorageImageAtomicDescriptorAlignmentUntypedPointers) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8_SINT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT); |
| desc_heap.WriteImageDescriptor(image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL); |
| desc_heap.WriteImageDescriptor(image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL); |
| |
| // [stride: spec_constant_id = 1] |
| // layout(descriptor_heap, r32i) uniform iimage1D si1[]; |
| // |
| // imageAtomicAdd(si1[1], 1, 1); // bad |
| // imageAtomicAdd(si1[0], 1, 1); // good |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability Image1D |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorateId %runtime_image ArrayStrideIdEXT %bad_stride |
| OpDecorate %bad_stride SpecId 1 |
| %void = OpTypeVoid |
| %4 = OpTypeFunction %void |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %uint = OpTypeInt 32 0 |
| %int = OpTypeInt 32 1 |
| %uint_0 = OpConstant %uint 0 |
| %uint_1 = OpConstant %uint 1 |
| %int_0 = OpConstant %int 0 |
| %int_1 = OpConstant %int 1 |
| %11 = OpTypeImage %int 1D 0 0 0 2 R32i |
| %_runtimearr_11 = OpTypeRuntimeArray %11 |
| %_ptr_Image_int = OpTypePointer Image %int |
| %_ptr_Image = OpTypeUntypedPointerKHR Image |
| %bad_stride = OpSpecConstant %uint 0 |
| %runtime_image = OpTypeRuntimeArray %11 |
| %main = OpFunction %void None %4 |
| %6 = OpLabel |
| %12 = OpUntypedAccessChainKHR %_ptr_UniformConstant %runtime_image %resource_heap %uint_1 |
| %19 = OpUntypedImageTexelPointerEXT %_ptr_Image %11 %12 %int_1 %uint_0 |
| %21 = OpAtomicIAdd %int %19 %uint_1 %uint_0 %int_1 |
| %23 = OpUntypedAccessChainKHR %_ptr_UniformConstant %runtime_image %resource_heap %uint_0 |
| %26 = OpUntypedImageTexelPointerEXT %_ptr_Image %11 %23 %int_1 %uint_0 |
| %27 = OpAtomicIAdd %int %26 %uint_1 %uint_0 %int_1 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| const uint32_t data = (uint32_t)heap_props.imageDescriptorSize - 1; |
| const VkSpecializationMapEntry entry = {1, 0, sizeof(uint32_t)}; |
| const VkSpecializationInfo specialization_info = {1, &entry, sizeof(uint32_t), &data}; |
| // spirv-val can detect this, but still want to test at GPU-AV time |
| m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineShaderStageCreateInfo-pSpecializationInfo-06849"); |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM, &specialization_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-imageDescriptorAlignment-11349"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceReservedRange) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if (heap_props.minResourceHeapReservedRange == 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = 0; // in reserved range |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, SamplerReservedRange) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| if (heap_props.minSamplerHeapReservedRange == 0) { |
| GTEST_SKIP() << "minSamplerHeapReservedRange is zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| const VkDeviceSize sampler_stride = heap_props.samplerDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| desc_heap.CreateSamplerHeap(sampler_stride, true); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| desc_heap.WriteImageDescriptor(image); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| desc_heap.WriteSamplerDescriptor(&sampler_info); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[0].sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[1].sourceData.constantOffset.heapOffset = 0; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D kTextures2D; |
| layout(set = 0, binding = 1) uniform sampler kSampler; |
| |
| void main() { |
| vec4 out_color = texture(sampler2D(kTextures2D, kSampler), vec2(0)); |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, IndirectIndexPushDataAlignment) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mapping.sourceData.indirectIndex.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mapping.sourceData.indirectIndex.pushOffset = 0; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| vkt::Buffer indirect_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| VkDeviceAddress indirect_address = indirect_buffer.Address() + 1; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11300"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, IndirectIndexPushDataAlignment2) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mapping.sourceData.indirectIndex.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mapping.sourceData.indirectIndex.pushOffset = 0; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| vkt::Buffer indirect_buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| uint32_t* indirect_data = (uint32_t*)indirect_buffer.Memory().Map(); |
| indirect_data[0] = 0; |
| indirect_data[1] = 0; |
| VkDeviceAddress indirect_address_0 = indirect_buffer.Address(); |
| VkDeviceAddress indirect_address_1 = indirect_buffer.Address() + 4; |
| VkDeviceAddress indirect_address_2 = 0x12340001; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address_0); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address_1); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| // bad |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address_2); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| // good again |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address_1); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| // VUID-vkCmdDispatch-None-11300 |
| m_errorMonitor->SetDesiredError("VkDeviceAddress 0x12340001"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, PushDataNotSet) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = |
| MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| // only update one of the dwords to force it to be non-aligned |
| uint32_t bad_dword = 0x11111111; |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_command_buffer.PushData(0, sizeof(uint32_t), &bad_dword); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| // VUID-vkCmdDispatch-None-11300 |
| m_errorMonitor->SetDesiredError("because vkCmdPushDataEXT was not called and the undefined value"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, PushDataNotSetOOB) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize, true); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| // Will be OOB regardless |
| mapping.sourceData.pushIndex.heapOffset = (uint32_t)desc_heap.resource_heap_.CreateInfo().size * 2; |
| mapping.sourceData.pushIndex.heapArrayStride = 0; |
| mapping.sourceData.pushIndex.pushOffset = 8; |
| mapping.sourceData.pushIndex.heapIndexStride = 2; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| // VUID-vkCmdDispatch-None-11309 |
| m_errorMonitor->SetDesiredError("vkCmdPushDataEXT[8:11] was not called and the values are undefined"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, IndirectAddressPushDataAlignment) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = |
| MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| vkt::Buffer indirect_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| VkDeviceAddress indirect_address = indirect_buffer.Address() + 1; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11304"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, MappingAddressBufferAlignment) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| vkt::Buffer ubo_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ubo_buffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT; |
| mappings[0].sourceData.pushAddressOffset = 0; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT; |
| mappings[1].sourceData.pushAddressOffset = 8; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| layout(set = 0, binding = 1) uniform B { uint b; }; |
| void main() { |
| a = b; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| VkDeviceAddress ssbo_address = ssbo_buffer.Address() + 1; |
| VkDeviceAddress ubo_address = ubo_buffer.Address() + 0; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &ssbo_address); // bad |
| m_command_buffer.PushData(8, sizeof(VkDeviceAddress), &ubo_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| ssbo_address = ssbo_buffer.Address() + 0; |
| ubo_address = ubo_buffer.Address() + 1; |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &ssbo_address); |
| m_command_buffer.PushData(8, sizeof(VkDeviceAddress), &ubo_address); // bad |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11441"); // ubo |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11442"); // ssbo |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, MappingAddressBufferAlignmentHeap) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize * 2); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT; |
| mappings[0].sourceData.pushAddressOffset = 8; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_RESOURCE_HEAP_DATA_EXT; |
| mappings[1].sourceData.heapData.heapOffset = 0; |
| mappings[1].sourceData.heapData.pushOffset = 0; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| layout(set = 0, binding = 1) uniform B { uint b; }; |
| void main() { |
| a = b; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| uint32_t bad_offset = 1; |
| VkDeviceAddress ssbo_address = ssbo_buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(uint32_t), &bad_offset); |
| m_command_buffer.PushData(8, sizeof(VkDeviceAddress), &ssbo_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11441"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, MappingIndirectAddressBufferAlignment) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| vkt::Buffer ubo_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ubo_buffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT; |
| mappings[0].sourceData.indirectAddress.pushOffset = 0; |
| mappings[0].sourceData.indirectAddress.addressOffset = 0; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT; |
| mappings[1].sourceData.indirectAddress.pushOffset = 0; |
| mappings[1].sourceData.indirectAddress.addressOffset = 8; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| layout(set = 0, binding = 1) uniform B { uint b; }; |
| void main() { |
| a = b; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| vkt::Buffer indirect_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| VkDeviceAddress* indirect_data = (VkDeviceAddress*)indirect_buffer.Memory().Map(); |
| indirect_data[0] = ssbo_buffer.Address() + 1; |
| indirect_data[1] = ubo_buffer.Address(); |
| indirect_data[2] = ssbo_buffer.Address(); |
| indirect_data[3] = ubo_buffer.Address() + 1; |
| VkDeviceAddress indirect_address = indirect_buffer.Address(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| indirect_address += (sizeof(VkDeviceAddress) * 2); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11441"); // ubo |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11442"); // ssbo |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, IndirectIndexNullIndirect) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = |
| MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| VkDeviceAddress null_address = 0; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &null_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11301"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, PushAddressNullIndirect) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| VkDeviceAddress null_address = 0; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &null_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11302"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, IndirectAddressNullIndirect) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| VkDescriptorSetAndBindingMappingEXT mapping = |
| MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| VkDeviceAddress null_address = 0; |
| |
| vkt::Buffer indirect_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| VkDeviceAddress* indirect_data = (VkDeviceAddress*)indirect_buffer.Memory().Map(); |
| indirect_data[0] = null_address; |
| VkDeviceAddress indirect_address = indirect_buffer.Address(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &null_address); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11305"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11306"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, UseCombinedImageSamplerIndex) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.imageDescriptorSize * 3); |
| desc_heap.CreateSamplerHeap(heap_props.samplerDescriptorSize * 3); |
| |
| vkt::Buffer buffer(*m_device, sizeof(float) * 4u, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| desc_heap.WriteImageDescriptorAtOffset(image, heap_props.imageDescriptorSize); |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform sampler2D tex; |
| layout(set = 1, binding = 0) buffer ssbo { |
| vec4 data; |
| }; |
| void main() { |
| data = texture(tex, vec2(0.5f)); |
| } |
| )glsl"; |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0, 1, VK_SPIRV_RESOURCE_TYPE_COMBINED_SAMPLED_IMAGE_BIT_EXT); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| mappings[0].sourceData.pushIndex.heapOffset = 0; |
| mappings[0].sourceData.pushIndex.pushOffset = 8; |
| mappings[0].sourceData.pushIndex.heapIndexStride = (uint32_t)heap_props.imageDescriptorSize; |
| mappings[0].sourceData.pushIndex.useCombinedImageSamplerIndex = true; |
| mappings[0].sourceData.pushIndex.samplerPushOffset = 1; // ignored |
| mappings[0].sourceData.pushIndex.samplerHeapIndexStride = (uint32_t)heap_props.samplerDescriptorSize; |
| mappings[1] = MakeSetAndBindingMapping(1, 0); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT; |
| mappings[1].sourceData.pushAddressOffset = 0; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2u; |
| mapping_info.pMappings = mappings; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| VkDeviceAddress ssbo_address = buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &ssbo_address); |
| |
| uint32_t image_index = 1; |
| uint32_t sampler_index = 999; // bad |
| uint32_t combined_index = (image_index & 0xfffff) | ((sampler_index & 0xfff) << 20); |
| m_command_buffer.PushData(8, sizeof(uint32_t), &combined_index); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| vk::CmdDispatch(m_command_buffer, 1u, 1u, 1u); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, MappingBindingCountAlias) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 4, true); |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0, 5); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mapping.sourceData.constantOffset.heapArrayStride = (uint32_t)resource_stride; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; } x[2]; |
| layout(set = 0, binding = 2) buffer B { uint b; } y[3]; |
| void main() { |
| x[0].a = 2; |
| y[2].b = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| char const* cs_source2 = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer X { uint d; } x; |
| layout(set = 0, binding = 1) buffer Y { uint d; } y; |
| layout(set = 0, binding = 2) buffer Z { uint d; } z; |
| layout(set = 0, binding = 4) buffer W { uint d; } w; |
| void main() { |
| x.d = y.d + z.d + w.d; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe2(*m_device, cs_source2, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe2); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| |
| // Same things, just a different mapping |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_ARRAY_EXT; |
| mapping.sourceData.indirectIndexArray.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mapping.sourceData.indirectIndexArray.heapIndexStride = (uint32_t)resource_stride; |
| mapping.sourceData.indirectIndexArray.pushOffset = 0; |
| mapping.sourceData.indirectIndexArray.addressOffset = 4; |
| |
| vkt::HeapComputePipeline pipe3(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vkt::HeapComputePipeline pipe4(*m_device, cs_source2, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| vkt::Buffer ubo_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| uint32_t* ubo_data = (uint32_t*)ubo_buffer.Memory().Map(); |
| ubo_data[1] = 0; |
| ubo_data[2] = 1; |
| ubo_data[3] = 2; |
| ubo_data[4] = 3; |
| ubo_data[5] = 4; // OOB |
| VkDeviceAddress indirect_ubo_address = ubo_buffer.Address(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.PushData(0, 8, &indirect_ubo_address); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe3); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe4); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, DifferentMappingResourceMask) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2, true); |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0, 1, VK_SPIRV_RESOURCE_TYPE_READ_ONLY_STORAGE_BUFFER_BIT_EXT); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[0].sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[1] = MakeSetAndBindingMapping(0, 0, 1, VK_SPIRV_RESOURCE_TYPE_READ_WRITE_STORAGE_BUFFER_BIT_EXT); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[1].sourceData.constantOffset.heapOffset = (uint32_t)(heap_props.minResourceHeapReservedRange + (resource_stride * 10)); |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2u; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) readonly buffer A { uint a; } a; |
| layout(set = 0, binding = 0) writeonly buffer B { uint b; } b; |
| void main() { |
| b.b = a.a; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, PushDataPushIndex) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| mappings[0].sourceData.pushIndex.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[0].sourceData.pushIndex.heapArrayStride = 0; |
| mappings[0].sourceData.pushIndex.pushOffset = 80; |
| mappings[0].sourceData.pushIndex.heapIndexStride = 2; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| mappings[1].sourceData.pushIndex.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[1].sourceData.pushIndex.heapArrayStride = 0; |
| mappings[1].sourceData.pushIndex.pushOffset = 128; |
| mappings[1].sourceData.pushIndex.heapIndexStride = 1; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| layout(set = 0, binding = 1) buffer B { uint b; }; |
| void main() { |
| a = 2; |
| b = 4; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| uint32_t bad_push_index = 512; |
| m_command_buffer.PushData(80, sizeof(uint32_t), &bad_push_index); |
| uint32_t good_push_index = 512; |
| m_command_buffer.PushData(128, sizeof(uint32_t), &good_push_index); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| |
| // now again with the user making using of the push constant |
| char const* cs_source2 = R"glsl( |
| #version 450 |
| layout(push_constant) uniform PC { |
| uint data[20]; |
| }; |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| layout(set = 0, binding = 1) buffer B { uint b; }; |
| void main() { |
| a = data[3]; |
| b = data[19]; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe2(*m_device, cs_source2, SPV_ENV_VULKAN_1_0, &mapping_info); |
| m_command_buffer.Begin(); |
| uint32_t garbage[20]; |
| m_command_buffer.PushData(0, 80, garbage); |
| m_command_buffer.PushData(80, sizeof(uint32_t), &bad_push_index); |
| m_command_buffer.PushData(128, sizeof(uint32_t), &good_push_index); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, PushDataIndirectIndex) { |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mappings[0].sourceData.indirectIndex.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[0].sourceData.indirectIndex.pushOffset = 80; |
| mappings[0].sourceData.indirectIndex.heapIndexStride = 2; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mappings[1].sourceData.indirectIndex.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[1].sourceData.indirectIndex.pushOffset = 128; |
| mappings[1].sourceData.indirectIndex.heapIndexStride = 1; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(push_constant) uniform PC { |
| uint data[20]; |
| }; |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| layout(set = 0, binding = 1) buffer B { uint b; }; |
| void main() { |
| a = data[3]; |
| b = data[19]; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| vkt::Buffer indirect_buffer(*m_device, 256, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| uint32_t* indirect_data = (uint32_t*)indirect_buffer.Memory().Map(); |
| indirect_data[0] = 5000; |
| indirect_data[16] = 0; |
| VkDeviceAddress indirect_address_bad = indirect_buffer.Address(); |
| VkDeviceAddress indirect_address_good = indirect_buffer.Address() + (16 * sizeof(uint32_t)); |
| |
| m_command_buffer.Begin(); |
| uint32_t garbage[20]; |
| m_command_buffer.PushData(0, 80, garbage); |
| m_command_buffer.PushData(80, sizeof(VkDeviceAddress), &indirect_address_good); |
| m_command_buffer.PushData(128, sizeof(VkDeviceAddress), &indirect_address_bad); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceHeapDataOOB) { |
| TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/issues/4861"); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| vkt::DescriptorHeap desc_heap(*this); |
| // create an extra 256 bytes that we will not bind |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize + 512, true); |
| const VkDeviceSize min_alignment = m_device->Physical().limits_.minUniformBufferOffsetAlignment; |
| VkDeviceSize bound_size = Align(heap_props.minResourceHeapReservedRange + heap_props.bufferDescriptorSize, min_alignment); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[0].sourceData.constantOffset.heapOffset = (uint32_t)heap_props.minResourceHeapReservedRange; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_RESOURCE_HEAP_DATA_EXT; |
| mappings[1].sourceData.heapData.heapOffset = (uint32_t)bound_size; |
| mappings[1].sourceData.heapData.pushOffset = 0; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| layout(set = 0, binding = 1) uniform B { uint b; }; |
| void main() { |
| a = b; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange.address = desc_heap.resource_heap_.Address(); |
| bind_resource_info.heapRange.size = bound_size; |
| bind_resource_info.reservedRangeOffset = desc_heap.GetResourceHeapReservedRangeOffset(); |
| bind_resource_info.reservedRangeSize = heap_props.minResourceHeapReservedRange; |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| |
| uint32_t push_offset = 0; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &push_offset); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingNoDescriptor) { |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptorAtOffset(ssbo_buffer.AddressRange(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)resource_stride; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingWrongDescriptor) { |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| |
| if (vk::GetPhysicalDeviceDescriptorSizeEXT(Gpu(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) != |
| vk::GetPhysicalDeviceDescriptorSizeEXT(Gpu(), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)) { |
| GTEST_SKIP() << "Currently the find() on the GPU only checks a single size"; |
| } |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| VkDeviceSize offset_0 = desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| VkDeviceSize offset_1 = desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[2]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[0].sourceData.constantOffset.heapOffset = (uint32_t)offset_0; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[1].sourceData.constantOffset.heapOffset = (uint32_t)offset_1; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| layout(set = 0, binding = 1) uniform B { uint b; }; |
| void main() { |
| a = b; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingWrongDescriptorUntyped) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| |
| if (vk::GetPhysicalDeviceDescriptorSizeEXT(Gpu(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) != |
| vk::GetPhysicalDeviceDescriptorSizeEXT(Gpu(), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)) { |
| GTEST_SKIP() << "Currently the find() on the GPU only checks a single size"; |
| } |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride * 2); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_descriptor_heap : require |
| layout(descriptor_heap) buffer SSBO { uint data; } s_heap[]; |
| layout(descriptor_heap) uniform UBO { uint data; } u_heap[]; |
| void main() { |
| s_heap[0].data = u_heap[1].data; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingNoDescriptorUntypedSlang) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| // Because of -spirv-unified-descriptor-heap-stride |
| const VkDeviceSize resource_stride = std::max(heap_props.imageDescriptorSize, heap_props.bufferDescriptorSize); |
| desc_heap.CreateResourceHeap(resource_stride * 4); |
| |
| // Same shader as PositiveDescriptorHeapUntyped.SlangBasicBuffer |
| char const* cs_source = R"( |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpCapability Shader |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_storage_buffer_storage_class" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %slang_resourceHeap %g_Push |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %PushConstants_std430 Block |
| OpMemberDecorate %PushConstants_std430 0 Offset 0 |
| OpDecorateId %_runtimearr_18 ArrayStrideIdEXT %26 |
| OpDecorate %slang_resourceHeap BuiltIn ResourceHeapEXT |
| OpDecorate %_runtimearr_uint ArrayStride 4 |
| OpDecorate %RWStructuredBuffer Block |
| OpMemberDecorate %RWStructuredBuffer 0 Offset 0 |
| OpDecorate %_ptr_StorageBuffer_uint ArrayStride 4 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %uint = OpTypeInt 32 0 |
| %PushConstants_std430 = OpTypeStruct %uint |
| %_ptr_PushConstant_PushConstants_std430 = OpTypePointer PushConstant %PushConstants_std430 |
| %int = OpTypeInt 32 1 |
| %int_0 = OpConstant %int 0 |
| %_ptr_PushConstant_uint = OpTypePointer PushConstant %uint |
| %18 = OpTypeBufferEXT StorageBuffer |
| %float = OpTypeFloat 32 |
| %20 = OpTypeImage %float 2D 2 0 0 1 Unknown |
| %21 = OpTypeBufferEXT Uniform |
| %22 = OpConstantSizeOfEXT %uint %20 |
| %23 = OpConstantSizeOfEXT %uint %21 |
| %bool = OpTypeBool |
| %25 = OpSpecConstantOp %bool UGreaterThan %22 %23 |
| %26 = OpSpecConstantOp %uint Select %25 %22 %23 |
| %_runtimearr_18 = OpTypeRuntimeArray %18 |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %_runtimearr_uint = OpTypeRuntimeArray %uint |
| %RWStructuredBuffer = OpTypeStruct %_runtimearr_uint |
| %_ptr_StorageBuffer_RWStructuredBuffer = OpTypePointer StorageBuffer %RWStructuredBuffer |
| %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint |
| %uint_42 = OpConstant %uint 42 |
| %g_Push = OpVariable %_ptr_PushConstant_PushConstants_std430 PushConstant |
| %slang_resourceHeap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %main = OpFunction %void None %3 |
| %4 = OpLabel |
| %12 = OpAccessChain %_ptr_PushConstant_uint %g_Push %int_0 |
| %13 = OpLoad %uint %12 |
| %29 = OpUntypedAccessChainKHR %_ptr_UniformConstant %_runtimearr_18 %slang_resourceHeap %13 |
| %34 = OpBufferPointerEXT %_ptr_StorageBuffer_RWStructuredBuffer %29 |
| %36 = OpAccessChain %_ptr_StorageBuffer_uint %34 %int_0 %int_0 |
| %37 = OpLoad %uint %12 |
| %38 = OpIAdd %uint %uint_42 %37 |
| OpStore %36 %38 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| uint32_t index = 2; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &index); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingNoDescriptorCombinedImageSampler) { |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| const VkDeviceSize sampler_stride = heap_props.samplerDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride); |
| desc_heap.CreateSamplerHeap(sampler_stride * 4); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| |
| VkImageViewCreateInfo view_info = image.BasicViewCreatInfo(VK_IMAGE_ASPECT_COLOR_BIT); |
| VkImageDescriptorInfoEXT image_info = vku::InitStructHelper(); |
| image_info.pView = &view_info; |
| image_info.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
| VkHostAddressRangeEXT descriptor_host{desc_heap.resource_heap_data_, static_cast<size_t>(heap_props.imageDescriptorSize)}; |
| VkResourceDescriptorInfoEXT descriptor_info = vku::InitStructHelper(); |
| descriptor_info.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; |
| descriptor_info.data.pImage = &image_info; |
| vk::WriteResourceDescriptorsEXT(*m_device, 1, &descriptor_info, &descriptor_host); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform sampler2D tex; |
| void main() { |
| vec4 out_color = texture(tex, vec2(0.5f)); |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingNullDescriptor) { |
| AddRequiredExtensions(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::nullDescriptor); |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| |
| if (vk::GetPhysicalDeviceDescriptorSizeEXT(Gpu(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) != |
| vk::GetPhysicalDeviceDescriptorSizeEXT(Gpu(), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)) { |
| GTEST_SKIP() << "Currently the find() on the GPU only checks a single size"; |
| } |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride); |
| |
| // Not a storage, so might be the same, but we never see it to know |
| desc_heap.WriteNullDescriptorAtOffset(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 0; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingToManyDescriptors) { |
| const uint32_t limit = 256; |
| std::vector<VkLayerSettingEXT> layer_settings = { |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing_total_descriptors", VK_LAYER_SETTING_TYPE_UINT32_EXT, 1, &limit}}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap(layer_settings)); |
| const uint32_t buffer_size = 131072; |
| vkt::Buffer ssbo_buffer(*m_device, buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| |
| const uint32_t alignment = static_cast<uint32_t>(m_device->Physical().limits_.minStorageBufferOffsetAlignment); |
| VkDeviceAddressRangeKHR addr_range{}; |
| addr_range.size = alignment; |
| VkResourceDescriptorInfoEXT desc_info = vku::InitStructHelper(); |
| desc_info.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
| desc_info.data.pAddressRange = &addr_range; |
| uint8_t host_data[256]; |
| VkHostAddressRangeEXT desc_host_data{host_data, heap_props.bufferDescriptorSize}; |
| |
| m_errorMonitor->SetDesiredError("DESCRIPTOR-HASHING-LIMIT"); |
| for (uint32_t i = 0; i < buffer_size; i += alignment) { |
| addr_range.address = ssbo_buffer.Address() + i; |
| vk::WriteResourceDescriptorsEXT(*m_device, 1, &desc_info, &desc_host_data); |
| } |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingDeviceLocal) { |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| vkt::DescriptorHeap desc_heap(*this); |
| |
| VkDeviceSize resource_heap_size_app = Align(heap_props.bufferDescriptorSize, heap_props.bufferDescriptorAlignment); |
| resource_heap_size_app = Align(resource_heap_size_app, heap_props.imageDescriptorAlignment); |
| const VkDeviceSize resource_heap_size_driver = resource_heap_size_app + heap_props.minResourceHeapReservedRange; |
| |
| VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper(); |
| allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| vkt::Buffer descriptor_heap( |
| *m_device, resource_heap_size_driver, |
| VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_flag_info); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_debug_printf : enable |
| layout (set = 0, binding = 0) buffer SSBO { uint a; }; |
| void main() { |
| a = 0; |
| } |
| )glsl"; |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange.address = descriptor_heap.Address(); |
| bind_resource_info.heapRange.size = resource_heap_size_driver; |
| bind_resource_info.reservedRangeOffset = resource_heap_size_app; |
| bind_resource_info.reservedRangeSize = heap_props.minResourceHeapReservedRange; |
| |
| { |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Update on the GPU with the wrong descriptor |
| if (vk::GetPhysicalDeviceDescriptorSizeEXT(Gpu(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) == |
| vk::GetPhysicalDeviceDescriptorSizeEXT(Gpu(), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)) { |
| vkt::Buffer ubo(*m_device, 16, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer copy_buffer(*m_device, 256, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, kHostVisibleMemProps); |
| VkHostAddressRangeEXT descriptor_host{copy_buffer.Memory().Map(), static_cast<size_t>(heap_props.bufferDescriptorSize)}; |
| VkDeviceAddressRangeEXT device_range = ubo.AddressRange(); |
| VkResourceDescriptorInfoEXT descriptor_info = vku::InitStructHelper(); |
| descriptor_info.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; |
| descriptor_info.data.pAddressRange = &device_range; |
| vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &descriptor_host); |
| |
| VkBufferCopy copy_region{0, 0, heap_props.bufferDescriptorSize}; |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| vk::CmdCopyBuffer(m_command_buffer, copy_buffer, descriptor_heap, 1u, ©_region); |
| m_command_buffer.FullMemoryBarrier(); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBWithHashingOn) { |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| desc_heap.CreateResourceHeap(resource_stride, true); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = (uint32_t)desc_heap.resource_heap_.CreateInfo().size + 4096; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer A { uint a; }; |
| void main() { |
| a = 2; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HardcodedOffsetOOB) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| if (desc_heap.resource_heap_.CreateInfo().size > 131072) { |
| GTEST_SKIP() << "too much reserved range"; |
| } |
| |
| vkt::Buffer ssbo_buffer(*m_device, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| // What the shader looks like |
| // |
| // layout(descriptor_heap) struct { |
| // layout(offset = 0) buffer a { uint data; } x; |
| // layout(offset = 131072) buffer b { uint data; } y; |
| // }; |
| // layout(push_constant) uniform PushConstant { uint payload; }; |
| // void main() { |
| // heap.y.data = heap.x.data; |
| // } |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorate %A Block |
| OpMemberDecorate %A 0 Offset 0 |
| |
| ; Use hardcoded offset |
| OpMemberDecorate %heap_struct 0 Offset 0 |
| OpMemberDecorate %heap_struct 1 Offset 131072 |
| |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %int = OpTypeInt 32 1 |
| %int_0 = OpConstant %int 0 |
| %int_1 = OpConstant %int 1 |
| %int_2 = OpConstant %int 2 |
| %uint = OpTypeInt 32 0 |
| %A = OpTypeStruct %uint |
| %_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer |
| %21 = OpTypeBufferEXT StorageBuffer |
| %heap_struct = OpTypeStruct %21 %21 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %20 = OpUntypedAccessChainKHR %_ptr_UniformConstant %heap_struct %resource_heap %int_0 |
| %24 = OpBufferPointerEXT %_ptr_StorageBuffer %20 |
| %25 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %A %24 %int_0 |
| %30 = OpUntypedAccessChainKHR %_ptr_UniformConstant %heap_struct %resource_heap %int_1 |
| %34 = OpBufferPointerEXT %_ptr_StorageBuffer %30 |
| %35 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %A %34 %int_0 |
| %load = OpLoad %uint %35 |
| OpStore %25 %load |
| OpReturn |
| OpFunctionEnd |
| |
| )"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_3, nullptr, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Currently don't handle logic to get stride of multiple arrays |
| TEST_F(NegativeGpuAVDescriptorHeap, DISABLED_MultidimensionalArrayOOB) { |
| TEST_DESCRIPTION("https://gitlab.khronos.org/Tracker/vk-gl-cts/-/issues/6645"); |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| // To hard to test OOB with reserved range |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| // one less than needed |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize * 4); |
| |
| // layout(descriptor_heap) buffer Heap { uint data; } heap[3][3]; |
| // void main() { |
| // heap[1][2].data = 42; |
| // } |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorate %Heap Block |
| OpMemberDecorate %Heap 0 Offset 0 |
| OpDecorateId %in_array ArrayStrideIdEXT %buf_size |
| OpDecorateId %out_array ArrayStrideIdEXT %stride_3 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %int = OpTypeInt 32 1 |
| %uint = OpTypeInt 32 0 |
| %uint_0 = OpConstant %uint 0 |
| %uint_1 = OpConstant %uint 1 |
| %uint_2 = OpConstant %uint 2 |
| %uint_3 = OpConstant %uint 3 |
| %uint_42 = OpConstant %uint 42 |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %Heap = OpTypeStruct %uint |
| %_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer |
| %buf_type = OpTypeBufferEXT StorageBuffer |
| %buf_size = OpConstantSizeOfEXT %uint %buf_type |
| %stride_3 = OpSpecConstantOp %int IMul %buf_size %uint_3 |
| %in_array = OpTypeArray %buf_type %uint_3 |
| %out_array = OpTypeArray %in_array %uint_3 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %15 = OpUntypedAccessChainKHR %_ptr_UniformConstant %out_array %resource_heap %uint_1 %uint_2 |
| %19 = OpBufferPointerEXT %_ptr_StorageBuffer %15 |
| %20 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %Heap %19 %uint_0 |
| OpStore %20 %uint_42 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, HashingCombinedSampler) { |
| const VkLayerSettingEXT layer_setting{OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}; |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap({layer_setting})); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.imageDescriptorSize); |
| desc_heap.CreateSamplerHeap(heap_props.samplerDescriptorSize); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| desc_heap.WriteImageDescriptor(image); |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform sampler2D tex; |
| void main() { |
| vec4 data = texture(tex, vec2(0.5f)); |
| } |
| )glsl"; |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_buffer); |
| vk::CmdDispatch(m_command_buffer, 1u, 1u, 1u); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-12472"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVDescriptorHeap, UntypedHardcodedArrayStride) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| const VkDeviceSize resource_stride = 256; // the max any descriptor can be |
| desc_heap.CreateResourceHeap(resource_stride); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| // layout(descriptor_heap, array_stride = 256) buffer SSBO { uint data; } heap[]; |
| // void main() { |
| // heap[0].data = 1; |
| // heap[20000].data = 1; |
| // } |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %resource_heap |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorate %SSBO Block |
| OpMemberDecorate %SSBO 0 Offset 0 |
| OpDecorate %runtime_array ArrayStride 256 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %int = OpTypeInt 32 1 |
| %uint = OpTypeInt 32 0 |
| %int_0 = OpConstant %int 0 |
| %uint_1 = OpConstant %uint 1 |
| %int_20000 = OpConstant %int 20000 |
| %SSBO = OpTypeStruct %uint |
| %_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant |
| %resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant |
| %_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer |
| %16 = OpTypeBufferEXT StorageBuffer |
| %runtime_array = OpTypeRuntimeArray %16 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %15 = OpUntypedAccessChainKHR %_ptr_UniformConstant %runtime_array %resource_heap %int_0 |
| %19 = OpBufferPointerEXT %_ptr_StorageBuffer %15 |
| %20 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO %19 %int_0 |
| OpStore %20 %uint_1 |
| %24 = OpUntypedAccessChainKHR %_ptr_UniformConstant %runtime_array %resource_heap %int_20000 |
| %27 = OpBufferPointerEXT %_ptr_StorageBuffer %24 |
| %28 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO %27 %int_0 |
| OpStore %28 %uint_1 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, nullptr, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |