| /* |
| * 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 |
| */ |
| // stype-check off |
| #include <spirv-tools/libspirv.h> |
| #include <vulkan/vulkan_core.h> |
| #include <cstdint> |
| #include <cstring> |
| #include "layer_validation_tests.h" |
| #include "descriptor_helper.h" |
| #include "generated/vk_function_pointers.h" |
| #include "pipeline_helper.h" |
| #include "shader_helper.h" |
| #include "shader_templates.h" |
| #include "test_framework.h" |
| #include "utils/math_utils.h" |
| #include "descriptor_heap_object.h" |
| #include "ray_tracing_objects.h" |
| |
| static const VkLayerSettingEXT kAllDumpSettings[3] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_device_generated_commands", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "gpu_dump_copy_memory_indirect", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT kAllDumpSettingCi = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 3, kAllDumpSettings}; |
| |
| class NegativeGpuDump : public VkLayerTest { |
| public: |
| void InitDescriptorBuffer(VkLayerSettingsCreateInfoEXT* custom_setting = nullptr); |
| void InitDescriptorHeap(VkLayerSettingsCreateInfoEXT* custom_setting = nullptr); |
| VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props = vku::InitStructHelper(); |
| VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer_props = vku::InitStructHelper(); |
| }; |
| |
| void NegativeGpuDump::InitDescriptorBuffer(VkLayerSettingsCreateInfoEXT* custom_setting) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBuffer); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| RETURN_IF_SKIP(InitFramework(custom_setting ? custom_setting : &kAllDumpSettingCi)); |
| RETURN_IF_SKIP(InitState()); |
| |
| GetPhysicalDeviceProperties2(descriptor_buffer_props); |
| } |
| |
| void NegativeGpuDump::InitDescriptorHeap(VkLayerSettingsCreateInfoEXT* custom_setting) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::descriptorHeap); |
| AddRequiredFeature(vkt::Feature::runtimeDescriptorArray); |
| RETURN_IF_SKIP(InitFramework(custom_setting ? custom_setting : &kAllDumpSettingCi)); |
| RETURN_IF_SKIP(InitState()); |
| |
| GetPhysicalDeviceProperties2(heap_props); |
| } |
| |
| TEST_F(NegativeGpuDump, Descriptors) { |
| RETURN_IF_SKIP(InitDescriptorBuffer()); |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| vkt::Buffer buffer_data(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_data, 16); |
| |
| void* mapped_descriptor_data = descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_props.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| }; |
| void main() { |
| a = 0; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorBufferWithoutDescriptor) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12250"); |
| RETURN_IF_SKIP(InitDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| vkt::Buffer descriptor_buffer(*m_device, 256, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| const char* vs_source = R"glsl( |
| #version 450 |
| layout(push_constant) uniform PushConstants { |
| vec4 x; |
| } pc; |
| |
| void main() { |
| gl_Position = pc.x; |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vs_source, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPushConstantRange pc_range = {VK_SHADER_STAGE_VERTEX_BIT, 0, 16}; |
| VkPipelineLayoutCreateInfo pipe_layout_ci = vku::InitStructHelper(); |
| pipe_layout_ci.pushConstantRangeCount = 1; |
| pipe_layout_ci.pPushConstantRanges = &pc_range; |
| vkt::PipelineLayout pipeline_layout(*m_device, pipe_layout_ci); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| float data[4] = {1.0, 2.0, 3.0, 4.0}; |
| vk::CmdPushConstants(m_command_buffer, pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 16, &data); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| m_errorMonitor->SetDesiredInfo("No VkPipelineLayout found"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorBufferWrongBindPoint) { |
| RETURN_IF_SKIP(InitDescriptorBuffer()); |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| vkt::Buffer descriptor_buffer(*m_device, 256, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| }; |
| void main() { |
| a = 0; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| // from core checks, which the user might not see |
| m_errorMonitor->SetAllowedFailureMsg("WARNING-Missing-vkCmdSetDescriptorBufferOffsets"); |
| m_errorMonitor->SetDesiredWarning("vkCmdSetDescriptorBufferOffsetsEXT was called with VK_PIPELINE_BIND_POINT_GRAPHICS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorBufferNoDescriptor) { |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorBuffer(&layer_setting_ci)); |
| |
| vkt::DescriptorSetLayout ds_layout(*m_device, {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| vkt::Buffer descriptor_buffer(*m_device, 256, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| }; |
| void main() { |
| a = 0; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| m_errorMonitor->SetDesiredWarning("NO DESCRIPTOR"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| // closet we will get to VU 08053/08054 |
| TEST_F(NegativeGpuDump, DescriptorBufferWrongBufferType) { |
| RETURN_IF_SKIP(InitDescriptorBuffer()); |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings = { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, // unused |
| }; |
| std::vector<VkDescriptorSetLayoutBinding> sampler_binding = { |
| {2, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }; |
| vkt::DescriptorSetLayout ds_layout(*m_device, bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::DescriptorSetLayout sampler_ds_layout(*m_device, sampler_binding, |
| VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout, &sampler_ds_layout}); |
| |
| vkt::Buffer sampler_descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| vkt::Buffer resource_descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout(set = 1, binding = 2) uniform sampler s; |
| layout(set = 0, binding = 0) uniform texture2D t; |
| layout(set = 0, binding = 1) buffer SSBO { vec4 result; }; |
| |
| void main() { |
| result = texture(sampler2D(t, s), vec2(0)); |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info[2]; |
| descriptor_buffer_binding_info[0] = vku::InitStructHelper(); |
| descriptor_buffer_binding_info[0].address = sampler_descriptor_buffer.Address(); |
| descriptor_buffer_binding_info[0].usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; |
| descriptor_buffer_binding_info[1] = vku::InitStructHelper(); |
| descriptor_buffer_binding_info[1].address = resource_descriptor_buffer.Address(); |
| descriptor_buffer_binding_info[1].usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 2, descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index[2] = {0, 1}; |
| VkDeviceSize buffer_offset[2] = {0, 0}; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 2, buffer_index, |
| buffer_offset); |
| |
| m_errorMonitor->SetDesiredWarning("BUFFER USAGE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, CopyMemoryIndirect) { |
| AddRequiredExtensions(VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::indirectMemoryCopy); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| RETURN_IF_SKIP(InitFramework(&kAllDumpSettingCi)); |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::Buffer src_buffer(*m_device, 1024, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, vkt::device_address); |
| vkt::Buffer dst_buffer(*m_device, 1024, VK_BUFFER_USAGE_TRANSFER_DST_BIT, vkt::device_address); |
| |
| const VkDeviceAddress src_address = src_buffer.Address(); |
| const VkDeviceAddress dst_address = dst_buffer.Address(); |
| VkCopyMemoryIndirectCommandKHR cmds[6] = {{src_address + 0, dst_address, 4}, {src_address + 32, dst_address + 32, 32}, |
| {src_address + 0, dst_address + 64, 16}, {src_address + 64, dst_address + 128, 64}, |
| {src_address + 0, dst_address + 256, 16}, {src_address + 128, dst_address + 512, 4}}; |
| const VkDeviceSize indirect_buffer_size = sizeof(cmds); |
| |
| vkt::Buffer indirect_buffer(*m_device, 1024, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, vkt::device_address); |
| void* indirect_buffer_data = indirect_buffer.Memory().Map(); |
| memcpy(indirect_buffer_data, cmds, indirect_buffer_size); |
| |
| VkStridedDeviceAddressRangeKHR address_range = {}; |
| address_range.address = indirect_buffer.Address(); |
| address_range.size = indirect_buffer_size; |
| address_range.stride = sizeof(VkCopyMemoryIndirectCommandKHR); |
| |
| VkCopyMemoryIndirectInfoKHR copy_info = vku::InitStructHelper(); |
| copy_info.copyCount = 6; |
| copy_info.copyAddressRange = address_range; |
| copy_info.srcCopyFlags = VK_ADDRESS_COPY_DEVICE_LOCAL_BIT_KHR; |
| copy_info.dstCopyFlags = VK_ADDRESS_COPY_DEVICE_LOCAL_BIT_KHR; |
| |
| m_command_buffer.Begin(); |
| vk::CmdCopyMemoryIndirectKHR(m_command_buffer, ©_info); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapDescriptorIndexing) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Alignment not reliable on MockICD"; |
| } |
| |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| 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(); |
| memset((void*)ubo_data, 0, 64); |
| ubo_data[0] = (uint32_t)resource_stride; |
| ubo_data[1] = (uint32_t)resource_stride * 2; |
| ubo_data[3] = (uint32_t)resource_stride * 8; |
| ubo_data[5] = (uint32_t)resource_stride * 8; |
| |
| const char* cs_source_static = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| } ssbo[8]; |
| |
| void main() { |
| ssbo[0].data = 0; |
| } |
| )glsl"; |
| const char* cs_source_runtime = R"glsl( |
| #version 450 |
| #extension GL_EXT_nonuniform_qualifier : enable |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint index; |
| uint data; |
| } ssbo[]; |
| |
| void main() { |
| ssbo[ssbo[0].index].data = 0; |
| } |
| )glsl"; |
| m_command_buffer.Begin(); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = 0; |
| mapping.sourceData.constantOffset.heapArrayStride = (uint32_t)resource_stride; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| // CONSTANT_DATA Static array, can detect OOB |
| vkt::HeapComputePipeline pipe1(*m_device, cs_source_static, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe1); |
| m_errorMonitor->SetDesiredWarning("OUT OF BOUNDS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| // CONSTANT_DATA runtime array, can't detect OOB |
| vkt::HeapComputePipeline pipe2(*m_device, cs_source_runtime, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe2); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| uint32_t push_data_uint = 1; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &push_data_uint); |
| |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| mapping.sourceData.pushIndex.heapOffset = 0; |
| mapping.sourceData.pushIndex.pushOffset = 0; |
| mapping.sourceData.pushIndex.heapIndexStride = (uint32_t)resource_stride; // start at SSBO[1] |
| mapping.sourceData.pushIndex.heapArrayStride = (uint32_t)resource_stride; |
| |
| // PUSH_INDEX Static array |
| vkt::HeapComputePipeline pipe3(*m_device, cs_source_static, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe3); |
| m_errorMonitor->SetDesiredWarning("OUT OF BOUNDS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| // PUSH_INDEX runtime array |
| vkt::HeapComputePipeline pipe4(*m_device, cs_source_runtime, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe4); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| VkDeviceAddress indirect_ubo_address = ubo_buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_ubo_address); |
| |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mapping.sourceData.indirectIndex.heapOffset = 0; |
| mapping.sourceData.indirectIndex.pushOffset = 0; |
| mapping.sourceData.indirectIndex.addressOffset = 4; // start at SSBO[2] |
| mapping.sourceData.indirectIndex.heapIndexStride = 1; |
| mapping.sourceData.indirectIndex.heapArrayStride = (uint32_t)resource_stride; |
| // INDIRECT_INDEX Static array |
| vkt::HeapComputePipeline pipe5(*m_device, cs_source_static, SPV_ENV_VULKAN_1_0, &mapping_info); |
| // INDIRECT_INDEX runtime array |
| vkt::HeapComputePipeline pipe6(*m_device, cs_source_runtime, SPV_ENV_VULKAN_1_0, &mapping_info); |
| |
| if (m_device->Physical().limits_.minUniformBufferOffsetAlignment <= 4) { |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe5); |
| m_errorMonitor->SetDesiredWarning("OUT OF BOUNDS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe6); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_ARRAY_EXT; |
| mapping.sourceData.indirectIndexArray.heapOffset = 0; |
| mapping.sourceData.indirectIndexArray.pushOffset = 0; |
| mapping.sourceData.indirectIndexArray.addressOffset = 0; |
| mapping.sourceData.indirectIndexArray.heapIndexStride = 1; |
| mapping.sourceData.indirectIndexArray.pEmbeddedSampler = nullptr; |
| |
| // INDIRECT_INDEX_ARRAY Static array |
| vkt::HeapComputePipeline pipe7(*m_device, cs_source_static, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe7); |
| m_errorMonitor->SetDesiredWarning("OUT OF BOUNDS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| // INDIRECT_INDEX_ARRAY runtime array |
| vkt::HeapComputePipeline pipe8(*m_device, cs_source_runtime, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe8); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapReservedRangeNonArray) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| }; |
| |
| void main() { |
| data = 0; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| bind_resource_info.reservedRangeOffset = 0; |
| bind_resource_info.reservedRangeSize = (uint32_t)resource_stride; |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = 0; |
| mapping.sourceData.constantOffset.heapArrayStride = (uint32_t)resource_stride; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("RESERVED RANGE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapReservedRangeArray) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| } x[4]; |
| |
| void main() { |
| x[0].data = 0; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| |
| VkDeviceSize max_descriptor_alignement = std::max(heap_props.bufferDescriptorAlignment, heap_props.imageDescriptorAlignment); |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| bind_resource_info.reservedRangeOffset = (uint32_t)max_descriptor_alignement; |
| bind_resource_info.reservedRangeSize = (uint32_t)resource_stride * 2; |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = 0; |
| mapping.sourceData.constantOffset.heapArrayStride = (uint32_t)resource_stride; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("RESERVED RANGE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapReservedRangeArrayIndexed) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| } x[4]; |
| |
| void main() { |
| x[0].data = 0; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| |
| 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(); |
| memset((void*)ubo_data, 0, 64); |
| ubo_data[0] = 0; |
| ubo_data[1] = (uint32_t)resource_stride; |
| ubo_data[2] = (uint32_t)resource_stride * 2; |
| ubo_data[3] = (uint32_t)resource_stride * 3; |
| |
| VkDeviceSize max_descriptor_alignement = std::max(heap_props.bufferDescriptorAlignment, heap_props.imageDescriptorAlignment); |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| bind_resource_info.reservedRangeOffset = (uint32_t)max_descriptor_alignement; |
| bind_resource_info.reservedRangeSize = (uint32_t)resource_stride * 2; |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| |
| VkDeviceAddress indirect_ubo_address = ubo_buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_ubo_address); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mapping.sourceData.indirectIndex.heapIndexStride = 1; |
| mapping.sourceData.indirectIndex.heapArrayStride = (uint32_t)resource_stride; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("RESERVED RANGE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapReservedRangeIndirectArray) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| } x[4]; |
| |
| void main() { |
| x[0].data = 0; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| |
| 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(); |
| memset((void*)ubo_data, 0, 64); |
| ubo_data[0] = (uint32_t)resource_stride * 2; |
| ubo_data[1] = (uint32_t)resource_stride * 3; |
| ubo_data[2] = 0; |
| ubo_data[3] = (uint32_t)resource_stride; |
| |
| VkDeviceAddress indirect_ubo_address = ubo_buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_ubo_address); |
| |
| VkDeviceSize max_descriptor_alignement = std::max(heap_props.bufferDescriptorAlignment, heap_props.imageDescriptorAlignment); |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| bind_resource_info.reservedRangeOffset = (uint32_t)max_descriptor_alignement; |
| bind_resource_info.reservedRangeSize = (uint32_t)resource_stride * 2; |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_ARRAY_EXT; |
| mapping.sourceData.indirectIndexArray.heapIndexStride = 1; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("RESERVED RANGE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapSampler) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| if (heap_props.minResourceHeapReservedRange != 0 || heap_props.minSamplerHeapReservedRange != 0) { |
| GTEST_SKIP() << "heapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.samplerDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 2), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| desc_heap.CreateSamplerHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D t; |
| layout(set = 0, binding = 1) uniform sampler s[64]; |
| void main() { |
| vec4 data = texture(sampler2D(t, s[2]), vec2(0.5f)); |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_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 = 0; |
| mappings[0].sourceData.constantOffset.heapArrayStride = 0; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[1].sourceData.constantOffset.heapOffset = 0; |
| mappings[1].sourceData.constantOffset.heapArrayStride = (uint32_t)resource_stride; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("OUT OF BOUNDS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapAlignment) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| }; |
| layout (set = 0, binding = 1) buffer SSBO_1 { |
| uint y; |
| } x[3]; |
| |
| void main() { |
| data = x[0].y; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| uint32_t push_data_uint = 1; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &push_data_uint); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0, 2); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT; |
| mapping.sourceData.pushIndex.heapOffset = 0; |
| mapping.sourceData.pushIndex.pushOffset = 0; |
| mapping.sourceData.pushIndex.heapIndexStride = 1; |
| mapping.sourceData.pushIndex.heapArrayStride = (uint32_t)resource_stride; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("MISALIGNED"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapAlignmentIndirectArray) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 5), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| } x[4]; |
| |
| void main() { |
| x[0].data = 0; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| |
| 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(); |
| memset((void*)ubo_data, 0, 64); |
| ubo_data[0] = (uint32_t)resource_stride * 2; |
| ubo_data[1] = (uint32_t)resource_stride + 1; |
| ubo_data[2] = 0; |
| ubo_data[3] = (uint32_t)(resource_stride * 3) + 1; |
| |
| VkDeviceAddress indirect_ubo_address = ubo_buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_ubo_address); |
| |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_ARRAY_EXT; |
| mapping.sourceData.indirectIndexArray.heapIndexStride = 1; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("MISALIGNED"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapAlignmentHeapData) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform UBO_0 { |
| uint data; |
| }; |
| void main() { |
| uint x = data; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| uint32_t push_data_uint = 1; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &push_data_uint); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = |
| MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_RESOURCE_HEAP_DATA_EXT); |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| m_errorMonitor->SetDesiredWarning("MISALIGNED"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapWithoutDescriptor) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| InitRenderTarget(); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* vs_source = R"glsl( |
| #version 450 |
| layout(push_constant) uniform PushConstants { |
| vec4 x; |
| } pc; |
| |
| void main() { |
| gl_Position = pc.x; |
| } |
| )glsl"; |
| VkShaderObj vs(*m_device, vs_source, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj fs(*m_device, kMinimalShaderGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| VkPipelineShaderStageCreateInfo stages[2]; |
| stages[0] = vs.GetStageCreateInfo(); |
| stages[1] = fs.GetStageCreateInfo(); |
| |
| 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.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.stageCount = 2u; |
| pipe.gp_ci_.pStages = stages; |
| pipe.gp_ci_.layout = VK_NULL_HANDLE; |
| pipe.CreateGraphicsPipeline(false); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| float data[4] = {1.0, 2.0, 3.0, 4.0}; |
| m_command_buffer.PushData(0, 16, data); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| bind_resource_info.reservedRangeOffset = 0; |
| bind_resource_info.reservedRangeSize = (uint32_t)resource_stride; |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapAlignmentPushAddress) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| if (m_device->Physical().limits_.minStorageBufferOffsetAlignment == 1) { |
| GTEST_SKIP() << "minStorageBufferOffsetAlignment is 1"; |
| } |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| }; |
| |
| void main() { |
| data = 0; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| VkDeviceAddress read_address = ssbo_buffer.Address() + 1; |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &read_address); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT); |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("MISALIGNED"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapAlignmentIndirectAddress) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| if (m_device->Physical().limits_.minUniformBufferOffsetAlignment == 1) { |
| GTEST_SKIP() << "minUniformBufferOffsetAlignment is 1"; |
| } |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform UBO { |
| uint data; |
| }; |
| |
| void main() { |
| uint a = data; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| vkt::Buffer indirect_buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer ubo_buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| *((VkDeviceAddress*)indirect_buffer.Memory().Map()) = ubo_buffer.Address() + 1; |
| |
| VkDeviceAddress indirect_address = indirect_buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_address); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = |
| MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT); |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("MISALIGNED"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapAlignmentIndirectIndex) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| if (m_device->Physical().limits_.minUniformBufferOffsetAlignment == 1) { |
| GTEST_SKIP() << "minUniformBufferOffsetAlignment is 1"; |
| } |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform UBO { |
| uint data; |
| }; |
| |
| void main() { |
| uint a = data; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| vkt::Buffer ubo_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| |
| VkDeviceAddress indirect_ubo_address = ubo_buffer.Address() + 1; |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_ubo_address); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mapping.sourceData.indirectIndex.heapIndexStride = 0; |
| mapping.sourceData.indirectIndex.heapArrayStride = (uint32_t)resource_stride; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("MISALIGNED"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapIndirectIndexNoBuffer) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform UBO { |
| uint data; |
| }; |
| |
| void main() { |
| uint a = data; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| VkDeviceAddress indirect_ubo_address = 0xBEEE0000; |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_ubo_address); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mapping.sourceData.indirectIndex.heapIndexStride = 0; |
| mapping.sourceData.indirectIndex.heapArrayStride = (uint32_t)resource_stride; |
| mapping.sourceData.indirectIndex.addressOffset = 0x10000; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("[WARNING] No VkBuffer found at 0xbeef0000"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapCombinedImageSampler) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| InitRenderTarget(); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0 || heap_props.minSamplerHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange/minSamplerHeapReservedRange is not zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.imageDescriptorSize); |
| desc_heap.CreateSamplerHeap(heap_props.samplerDescriptorSize); |
| |
| 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); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDispatch(m_command_buffer, 1u, 1u, 1u); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapZeroArrayStride) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| } ssbo[8]; |
| |
| void main() { |
| ssbo[0].data = 0; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("ZERO ARRAY STRIDE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapIndirectIndexBufferType) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform UBO { |
| uint data; |
| }; |
| |
| void main() { |
| uint a = data; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| // should be a UNIFORM |
| vkt::Buffer bad_indirect_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| |
| VkDeviceAddress indirect_ubo_address = bad_indirect_buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_ubo_address); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT; |
| mapping.sourceData.indirectIndex.heapIndexStride = 0; |
| mapping.sourceData.indirectIndex.heapArrayStride = (uint32_t)resource_stride; |
| |
| 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); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("BUFFER TYPE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapPushAddressBufferType) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| const VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform UBO { uint a; }; |
| layout (set = 0, binding = 1) buffer SSBO { uint b; }; |
| |
| void main() { |
| b = a; |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_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 = 2u; |
| mapping_info.pMappings = mappings; |
| |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| vkt::Buffer ssbo_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer ubo_buffer(*m_device, 64, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| VkDeviceAddress indirect_ssbo_address = ssbo_buffer.Address(); |
| VkDeviceAddress indirect_ubo_address = ubo_buffer.Address(); |
| m_command_buffer.PushData(0, sizeof(VkDeviceAddress), &indirect_ssbo_address); |
| m_command_buffer.PushData(8, sizeof(VkDeviceAddress), &indirect_ubo_address); |
| |
| m_errorMonitor->SetDesiredWarning("BUFFER TYPE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapUntypedPointers) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0 || heap_props.minSamplerHeapReservedRange != 0) { |
| GTEST_SKIP() << "heapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| desc_heap.CreateSamplerHeap(heap_props.samplerDescriptorSize); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_descriptor_heap : require |
| #extension GL_EXT_nonuniform_qualifier : require |
| layout (set = 0, binding = 0) uniform UBO { uint a; }; |
| layout (set = 0, binding = 1) buffer SSBO { uint b; }; |
| layout(descriptor_heap) buffer Heap { uint c; } heap[]; |
| layout(descriptor_heap) uniform HeapX { uint d; } heapX[]; |
| layout(descriptor_heap) uniform texture2D heapT[]; |
| layout(descriptor_heap) uniform sampler heapS[]; |
| layout(push_constant) uniform PushConstant { |
| uint pc; |
| }; |
| void main() { |
| b = a; |
| heap[0].c = a; |
| heap[2].c = pc; |
| heap[2].c += 2; |
| uint x = heapX[b].d; |
| uint y = heapX[a].d; |
| uint z = heapX[114].d; |
| |
| vec4 data = texture(sampler2D(heapT[0], heapS[0]), vec2(0)); |
| vec4 data2 = texture(sampler2D(heapT[b], heapS[1]), vec2(0)); |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| desc_heap.BindSamplerHeap(m_command_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 = 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)resource_stride; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2u; |
| mapping_info.pMappings = mappings; |
| |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_3, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| uint32_t push_data = 0; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &push_data); |
| m_errorMonitor->SetDesiredWarning("OUT OF BOUNDS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapUntypedPointersStorageImage) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0 || heap_props.minSamplerHeapReservedRange != 0) { |
| GTEST_SKIP() << "heapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; |
| VkDeviceSize heap_size = Align((resource_stride * 4), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 460 core |
| #extension GL_EXT_descriptor_heap: enable |
| layout(descriptor_heap, r32i) uniform iimage1D si1[]; |
| layout(descriptor_heap, R32ui) uniform uimage2D si2[]; |
| layout(set = 0, binding = 0, r32i) uniform iimage1D si3[]; |
| layout(set = 0, binding = 1, R32ui) uniform uimage2D si4[]; |
| |
| void main() { |
| imageAtomicAdd(si1[2], 1, 1); |
| imageStore(si2[1], ivec2(1), uvec4(1)); |
| imageAtomicAdd(si3[0], 1, 1); |
| imageStore(si4[1], ivec2(1), uvec4(1)); |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_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 = 0; |
| mappings[0].sourceData.constantOffset.heapArrayStride = (uint32_t)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)resource_stride; |
| mappings[1].sourceData.constantOffset.heapArrayStride = (uint32_t)resource_stride; |
| |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2u; |
| mapping_info.pMappings = mappings; |
| |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_3, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| uint32_t push_data = 0; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &push_data); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapBindingCount) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| VkDeviceSize heap_size = Align((resource_stride * 3), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| 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[0].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); |
| m_errorMonitor->SetDesiredWarning("OUT OF BOUNDS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe2); |
| m_errorMonitor->SetDesiredWarning("OUT OF BOUNDS"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapUntypedPointersPushDataIndex) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(8192); |
| |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Alignment not reliable on MockICD"; |
| } |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_descriptor_heap : require |
| #extension GL_EXT_nonuniform_qualifier : require |
| layout(descriptor_heap) buffer Heap { uint x; } heap[]; |
| layout(push_constant) uniform PushConstant { |
| uint pc_0; |
| layout(offset = 32) uint pc_1; |
| uint pc_2; // offset 36 |
| }; |
| void main() { |
| heap[0].x = 0; |
| heap[pc_0].x = 1; |
| heap[pc_1].x = 2; |
| heap[pc_0 + pc_2].x = 3; |
| heap[pc_0 * pc_2 + pc_1].x = 4; |
| heap[pc_0 + 1].x = 5; |
| } |
| )glsl"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_3, nullptr); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| uint8_t unused[40]; |
| m_command_buffer.PushData(0, 40, unused); // avoid 11376 |
| uint32_t pc_0 = 2; |
| uint32_t pc_1 = 1; |
| uint32_t pc_2 = 3; |
| m_command_buffer.PushData(0, sizeof(uint32_t), &pc_0); |
| m_command_buffer.PushData(32, sizeof(uint32_t), &pc_1); |
| m_command_buffer.PushData(36, sizeof(uint32_t), &pc_2); |
| m_errorMonitor->SetDesiredInfo("array index: [1] (from vkCmdPushDataEXT[32:35])"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, UntypedPointersMultiDimensional) { |
| TEST_DESCRIPTION("https://gitlab.khronos.org/spirv/SPIR-V/-/issues/942"); |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| // We want to easily control it for testing |
| if (heap_props.minResourceHeapReservedRange != 0 || heap_props.minSamplerHeapReservedRange != 0) { |
| GTEST_SKIP() << "heapReservedRange is not zero"; |
| } |
| |
| const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; |
| VkDeviceSize heap_size = Align((resource_stride * 8), resource_stride); |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| // layout(descriptor_heap) buffer Heap { uint data; } heap[3][3]; |
| // void main() { |
| // heap[1][2].data = 42; |
| // } |
| 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 |
| OpDecorate %resource_heap BuiltIn ResourceHeapEXT |
| OpDecorate %Heap Block |
| OpMemberDecorate %Heap 0 Offset 0 |
| OpDecorateId %out_array ArrayStrideIdEXT %buf_size |
| OpDecorateId %in_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 |
| )asm"; |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_3, nullptr, SPV_SOURCE_ASM); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredInfo("array index: [1][2]"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapPushOffsetOOB) { |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.bufferDescriptorSize); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT; |
| mapping.sourceData.pushAddressOffset = 8; |
| |
| 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); |
| |
| uint32_t push_index = 0; |
| m_command_buffer.PushData(8, sizeof(uint32_t), &push_index); |
| VkDeviceAddress indirect_data = 0; |
| m_command_buffer.PushData(16, sizeof(VkDeviceAddress), &indirect_data); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("PUSH DATA"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapNoDescriptor) { |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorHeap(&layer_setting_ci)); |
| |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(1024); |
| |
| 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 = 3; |
| } |
| )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); |
| m_errorMonitor->SetDesiredWarning("NO DESCRIPTOR"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapWrongDescriptor) { |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorHeap(&layer_setting_ci)); |
| |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(1024); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| vkt::Buffer ssbo_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| desc_heap.WriteBufferDescriptor(ssbo_buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0, R32ui) uniform uimage2D si; |
| void main() { |
| imageStore(si, ivec2(1), uvec4(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); |
| m_errorMonitor->SetDesiredWarning("WRONG DESCRIPTOR"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapWrongDescriptorSampler) { |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorHeap(&layer_setting_ci)); |
| |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(1024); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1; |
| mapping_info.pMappings = &mapping; |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| VkHostAddressRangeEXT sampler_host{desc_heap.resource_heap_data_, heap_props.samplerDescriptorSize}; |
| vk::WriteSamplerDescriptorsEXT(*m_device, 1u, &sampler_info, &sampler_host); |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0, R32ui) uniform uimage2D si; |
| void main() { |
| imageStore(si, ivec2(1), uvec4(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); |
| m_errorMonitor->SetDesiredWarning("WRONG DESCRIPTOR"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapWrongDescriptorNotSampler) { |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorHeap(&layer_setting_ci)); |
| |
| if (heap_props.minResourceHeapReservedRange != 0 || heap_props.minSamplerHeapReservedRange != 0) { |
| GTEST_SKIP() << "heapReservedRange is not zero"; |
| } |
| |
| vkt::Buffer descriptor_heap_r(*m_device, 1024, VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT, vkt::device_address); |
| vkt::Buffer descriptor_heap_s(*m_device, 1024, VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT, vkt::device_address); |
| |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R8G8B8A8_SINT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| VkImageViewCreateInfo view_info = image.BasicViewCreatInfo(VK_IMAGE_ASPECT_COLOR_BIT); |
| void* heap_data = descriptor_heap_r.Memory().Map(); |
| VkHostAddressRangeEXT resource_host{heap_data, heap_props.imageDescriptorSize}; |
| VkImageDescriptorInfoEXT image_info = vku::InitStructHelper(); |
| image_info.pView = &view_info; |
| image_info.layout = VK_IMAGE_LAYOUT_GENERAL; |
| VkResourceDescriptorInfoEXT descriptor_info = vku::InitStructHelper(); |
| descriptor_info.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; |
| descriptor_info.data.pImage = &image_info; |
| vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &resource_host); |
| |
| heap_data = descriptor_heap_s.Memory().Map(); |
| resource_host.address = heap_data; |
| vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &resource_host); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D t; |
| layout(set = 0, binding = 1) uniform sampler s; |
| void main() { |
| vec4 data = texture(sampler2D(t, s), vec2(0.5f)); |
| } |
| )glsl"; |
| |
| m_command_buffer.Begin(); |
| |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange = descriptor_heap_r.AddressRange(); |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| |
| bind_resource_info.heapRange = descriptor_heap_s.AddressRange(); |
| vk::CmdBindSamplerHeapEXT(m_command_buffer, &bind_resource_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 = 0; |
| 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 = 2u; |
| mapping_info.pMappings = mappings; |
| |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_0, &mapping_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredWarning("WRONG DESCRIPTOR"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapNoDescriptorCombinedSampler) { |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorHeap(&layer_setting_ci)); |
| |
| if (heap_props.minResourceHeapReservedRange != 0 || heap_props.minSamplerHeapReservedRange != 0) { |
| GTEST_SKIP() << "heapReservedRange is not zero"; |
| } |
| |
| 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(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapWrongDescriptorDebugNames) { |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorHeap(&layer_setting_ci)); |
| |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(1024); |
| |
| 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 = 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)heap_props.bufferDescriptorSize; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 2; |
| mapping_info.pMappings = mappings; |
| |
| VkDebugUtilsObjectNameInfoEXT debug_obj_info = vku::InitStructHelper(); |
| debug_obj_info.objectHandle = 0; |
| debug_obj_info.objectType = VK_OBJECT_TYPE_UNKNOWN; |
| debug_obj_info.pObjectName = "My Sampler"; |
| |
| uint8_t* heap_data = desc_heap.resource_heap_data_; |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(&debug_obj_info); |
| VkHostAddressRangeEXT sampler_host{heap_data, heap_props.samplerDescriptorSize}; |
| vk::WriteSamplerDescriptorsEXT(*m_device, 1u, &sampler_info, &sampler_host); |
| |
| debug_obj_info.pObjectName = "My UBO"; |
| vkt::Buffer ssbo_buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| VkHostAddressRangeEXT descriptor_host{heap_data + heap_props.bufferDescriptorSize, heap_props.bufferDescriptorSize}; |
| VkDeviceAddressRangeEXT device_range = ssbo_buffer.AddressRange(); |
| VkResourceDescriptorInfoEXT descriptor_info = vku::InitStructHelper(&debug_obj_info); |
| descriptor_info.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; |
| descriptor_info.data.pAddressRange = &device_range; |
| vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &descriptor_host); |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0, R32ui) uniform uimage2D si; |
| layout(set = 0, binding = 1) uniform UBO { uvec4 data;}; |
| void main() { |
| imageStore(si, ivec2(1), data); |
| } |
| )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); |
| m_errorMonitor->SetDesiredWarning("[My Sampler]"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapHashConflict) { |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorHeap(&layer_setting_ci)); |
| |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| |
| // storage image and sampled image might be the exact same descriptor |
| uint8_t storage_descriptor[256]; |
| uint8_t sampled_descriptor[256]; |
| vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT); |
| VkImageViewCreateInfo view_info = image.BasicViewCreatInfo(VK_IMAGE_ASPECT_COLOR_BIT); |
| VkHostAddressRangeEXT resource_host{storage_descriptor, heap_props.imageDescriptorSize}; |
| VkImageDescriptorInfoEXT image_info = vku::InitStructHelper(); |
| image_info.pView = &view_info; |
| image_info.layout = VK_IMAGE_LAYOUT_GENERAL; |
| VkResourceDescriptorInfoEXT descriptor_info = vku::InitStructHelper(); |
| descriptor_info.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; |
| descriptor_info.data.pImage = &image_info; |
| vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &resource_host); |
| resource_host.address = sampled_descriptor; |
| descriptor_info.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; |
| vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &resource_host); |
| |
| if (memcmp(storage_descriptor, sampled_descriptor, heap_props.imageDescriptorSize) != 0) { |
| GTEST_SKIP() << "UBO and SSBO are different descriptors"; |
| } |
| |
| vkt::Buffer resource_heap(*m_device, 1024, VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT, vkt::device_address); |
| void* heap_data = resource_heap.Memory().Map(); |
| memcpy(heap_data, storage_descriptor, heap_props.imageDescriptorSize); |
| |
| vkt::Buffer sampler_heap(*m_device, 1024, VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT, vkt::device_address); |
| heap_data = sampler_heap.Memory().Map(); |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| VkHostAddressRangeEXT sampler_host{heap_data, heap_props.samplerDescriptorSize}; |
| vk::WriteSamplerDescriptorsEXT(*m_device, 1u, &sampler_info, &sampler_host); |
| |
| VkDescriptorSetAndBindingMappingEXT mappings[3]; |
| mappings[0] = MakeSetAndBindingMapping(0, 0); |
| mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[0].sourceData.constantOffset.heapOffset = 0; |
| mappings[1] = MakeSetAndBindingMapping(0, 1); |
| mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[1].sourceData.constantOffset.heapOffset = 0; |
| mappings[2] = MakeSetAndBindingMapping(0, 2); |
| mappings[2].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mappings[2].sourceData.constantOffset.heapOffset = 0; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 3; |
| mapping_info.pMappings = mappings; |
| |
| char const* cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 2) uniform sampler s; |
| layout(set = 0, binding = 0) uniform texture2D sampledImage; |
| layout(set = 0, binding = 1, rgba8) uniform image2D storageImage; |
| void main(){ |
| vec4 color = texture(sampler2D(sampledImage, s), vec2(0)); |
| imageStore(storageImage, ivec2(1), color); |
| } |
| )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 = resource_heap.AddressRange(); |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| bind_resource_info.heapRange = sampler_heap.AddressRange(); |
| vk::CmdBindSamplerHeapEXT(m_command_buffer, &bind_resource_info); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredInfo("GPU-DUMP"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, AccelStructPushAddressValid) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer); |
| |
| VkDebugUtilsObjectNameInfoEXT tlas_dbg_name = vku::InitStructHelper(); |
| tlas_dbg_name.objectType = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR; |
| tlas_dbg_name.pObjectName = "my_tlas"; |
| tlas_dbg_name.objectHandle = (uint64_t)tlas.GetDstAS()->handle(); |
| vk::SetDebugUtilsObjectNameEXT(device(), &tlas_dbg_name); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddCreateInfoFlags2(VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| vec3 ray_origin = vec3(0,0,-50); |
| vec3 ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,-50); |
| ray_direction = vec3(0,0,-1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,50); |
| ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| ray_origin = vec3(0,0,50); |
| ray_direction = vec3(0,0,-1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,0); |
| ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen, nullptr, &mapping_info); |
| |
| const char* miss = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| |
| void main() { |
| hit = vec3(0.1, 0.2, 0.3); |
| } |
| )glsl"; |
| pipeline.AddGlslMissShader(miss, nullptr, &mapping_info); |
| |
| const char* closest_hit = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| #extension GL_ARB_gpu_shader_int64 : enable |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| hitAttributeEXT vec2 baryCoord; |
| |
| void main() { |
| const vec3 barycentricCoords = vec3(1.0f - baryCoord.x - baryCoord.y, baryCoord.x, baryCoord.y); |
| hit = barycentricCoords; |
| } |
| )glsl"; |
| pipeline.AddGlslClosestHitShader(closest_hit, nullptr, &mapping_info); |
| pipeline.Build(); |
| |
| const uint32_t ray_gen_width = 1; |
| const uint32_t ray_gen_height = 4; |
| const uint32_t ray_gen_depth = 1; |
| |
| m_command_buffer.Begin(); |
| const VkDeviceAddress as_addr = tlas.GetDstAS()->GetAccelerationStructureDeviceAddress(); |
| m_command_buffer.PushData(0, sizeof(as_addr), &as_addr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| |
| m_errorMonitor->SetDesiredInfo("my_tlas"); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, ray_gen_width, ray_gen_height, ray_gen_depth); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, AccelStructPushAddressInvalid) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer); |
| |
| VkDebugUtilsObjectNameInfoEXT tlas_dbg_name = vku::InitStructHelper(); |
| tlas_dbg_name.objectType = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR; |
| tlas_dbg_name.pObjectName = "my_tlas"; |
| tlas_dbg_name.objectHandle = (uint64_t)tlas.GetDstAS()->handle(); |
| vk::SetDebugUtilsObjectNameEXT(device(), &tlas_dbg_name); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddCreateInfoFlags2(VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| vec3 ray_origin = vec3(0,0,-50); |
| vec3 ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,-50); |
| ray_direction = vec3(0,0,-1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,50); |
| ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| ray_origin = vec3(0,0,50); |
| ray_direction = vec3(0,0,-1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,0); |
| ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen, nullptr, &mapping_info); |
| |
| const char* miss = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| |
| void main() { |
| hit = vec3(0.1, 0.2, 0.3); |
| } |
| )glsl"; |
| pipeline.AddGlslMissShader(miss, nullptr, &mapping_info); |
| |
| const char* closest_hit = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| hitAttributeEXT vec2 baryCoord; |
| |
| void main() { |
| const vec3 barycentricCoords = vec3(1.0f - baryCoord.x - baryCoord.y, baryCoord.x, baryCoord.y); |
| hit = barycentricCoords; |
| } |
| )glsl"; |
| pipeline.AddGlslClosestHitShader(closest_hit, nullptr, &mapping_info); |
| pipeline.Build(); |
| |
| const uint32_t ray_gen_width = 1; |
| const uint32_t ray_gen_height = 4; |
| const uint32_t ray_gen_depth = 1; |
| |
| m_command_buffer.Begin(); |
| // Invalidate AS address |
| const VkDeviceAddress as_addr = tlas.GetDstAS()->GetAccelerationStructureDeviceAddress() + 256; |
| m_command_buffer.PushData(0, sizeof(as_addr), &as_addr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| |
| m_errorMonitor->SetDesiredWarning("No VkAccelerationStructureKHR found"); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, ray_gen_width, ray_gen_height, ray_gen_depth); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, AccelStructHeapIndirectAddressValid) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Test not supported by MockICD (TLAS address will end up being garbage)"; |
| } |
| |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer); |
| |
| VkDebugUtilsObjectNameInfoEXT tlas_dbg_name = vku::InitStructHelper(); |
| tlas_dbg_name.objectType = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR; |
| tlas_dbg_name.pObjectName = "my_tlas"; |
| tlas_dbg_name.objectHandle = (uint64_t)tlas.GetDstAS()->handle(); |
| vk::SetDebugUtilsObjectNameEXT(device(), &tlas_dbg_name); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = |
| MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddCreateInfoFlags2(VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| vec3 ray_origin = vec3(0,0,-50); |
| vec3 ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,-50); |
| ray_direction = vec3(0,0,-1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,50); |
| ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| ray_origin = vec3(0,0,50); |
| ray_direction = vec3(0,0,-1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,0); |
| ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen, nullptr, &mapping_info); |
| |
| const char* miss = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| |
| void main() { |
| hit = vec3(0.1, 0.2, 0.3); |
| } |
| )glsl"; |
| pipeline.AddGlslMissShader(miss, nullptr, &mapping_info); |
| |
| const char* closest_hit = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| #extension GL_ARB_gpu_shader_int64 : enable |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| hitAttributeEXT vec2 baryCoord; |
| |
| void main() { |
| const vec3 barycentricCoords = vec3(1.0f - baryCoord.x - baryCoord.y, baryCoord.x, baryCoord.y); |
| hit = barycentricCoords; |
| } |
| )glsl"; |
| pipeline.AddGlslClosestHitShader(closest_hit, nullptr, &mapping_info); |
| pipeline.Build(); |
| |
| const uint32_t ray_gen_width = 1; |
| const uint32_t ray_gen_height = 4; |
| const uint32_t ray_gen_depth = 1; |
| |
| const VkDeviceAddress as_addr = tlas.GetDstAS()->GetAccelerationStructureDeviceAddress(); |
| |
| vkt::Buffer indirect_buffer(*m_device, sizeof(VkDeviceAddress), |
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT, vkt::device_address); |
| auto indirect_buffer_ptr = (VkDeviceAddress*)indirect_buffer.Memory().Map(); |
| *indirect_buffer_ptr = as_addr; |
| indirect_buffer.Memory().Unmap(); |
| const VkDeviceAddress indirect_buffer_addr = indirect_buffer.Address(); |
| |
| m_command_buffer.Begin(); |
| |
| m_command_buffer.PushData(0, sizeof(indirect_buffer_addr), &indirect_buffer_addr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| |
| m_errorMonitor->SetDesiredInfo("my_tlas"); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, ray_gen_width, ray_gen_height, ray_gen_depth); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, AccelStructHeapIndirectAddressInvalid) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer); |
| |
| VkDebugUtilsObjectNameInfoEXT tlas_dbg_name = vku::InitStructHelper(); |
| tlas_dbg_name.objectType = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR; |
| tlas_dbg_name.pObjectName = "my_tlas"; |
| tlas_dbg_name.objectHandle = (uint64_t)tlas.GetDstAS()->handle(); |
| vk::SetDebugUtilsObjectNameEXT(device(), &tlas_dbg_name); |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = |
| MakeZeroSetAndBindingMapping(0, 0, VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT); |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddCreateInfoFlags2(VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| vec3 ray_origin = vec3(0,0,-50); |
| vec3 ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,-50); |
| ray_direction = vec3(0,0,-1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,50); |
| ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| ray_origin = vec3(0,0,50); |
| ray_direction = vec3(0,0,-1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| |
| // Will miss |
| ray_origin = vec3(0,0,0); |
| ray_direction = vec3(0,0,1); |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen, nullptr, &mapping_info); |
| |
| const char* miss = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| |
| void main() { |
| hit = vec3(0.1, 0.2, 0.3); |
| } |
| )glsl"; |
| pipeline.AddGlslMissShader(miss, nullptr, &mapping_info); |
| |
| const char* closest_hit = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| #extension GL_ARB_gpu_shader_int64 : enable |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| hitAttributeEXT vec2 baryCoord; |
| |
| void main() { |
| const vec3 barycentricCoords = vec3(1.0f - baryCoord.x - baryCoord.y, baryCoord.x, baryCoord.y); |
| hit = barycentricCoords; |
| } |
| )glsl"; |
| pipeline.AddGlslClosestHitShader(closest_hit, nullptr, &mapping_info); |
| pipeline.Build(); |
| |
| const uint32_t ray_gen_width = 1; |
| const uint32_t ray_gen_height = 4; |
| const uint32_t ray_gen_depth = 1; |
| |
| const VkDeviceAddress as_addr = tlas.GetDstAS()->GetAccelerationStructureDeviceAddress(); |
| |
| vkt::Buffer indirect_buffer(*m_device, sizeof(VkDeviceAddress), |
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT, vkt::device_address); |
| auto indirect_buffer_ptr = (VkDeviceAddress*)indirect_buffer.Memory().Map(); |
| // Invalid AS addr |
| *indirect_buffer_ptr = as_addr + 256; |
| indirect_buffer.Memory().Unmap(); |
| const VkDeviceAddress indirect_buffer_addr = indirect_buffer.Address(); |
| |
| m_command_buffer.Begin(); |
| |
| m_command_buffer.PushData(0, sizeof(indirect_buffer_addr), &indirect_buffer_addr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| |
| m_errorMonitor->SetDesiredWarning("No VkAccelerationStructureKHR found"); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, ray_gen_width, ray_gen_height, ray_gen_depth); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapNullDescriptor) { |
| AddRequiredExtensions(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::nullDescriptor); |
| static const VkLayerSettingEXT layer_settings[2] = { |
| {OBJECT_LAYER_NAME, "gpu_dump_descriptors", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| {OBJECT_LAYER_NAME, "descriptor_hashing", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}, |
| }; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 2, layer_settings}; |
| RETURN_IF_SKIP(InitDescriptorHeap(&layer_setting_ci)); |
| |
| if (heap_props.minResourceHeapReservedRange != 0) { |
| GTEST_SKIP() << "minResourceHeapReservedRange is not zero"; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(1024); |
| desc_heap.WriteNullDescriptorAtOffset(VK_DESCRIPTOR_TYPE_STORAGE_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 SSBO { uint x; }; |
| void main() { |
| x = 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); |
| m_errorMonitor->SetDesiredInfo("Null Descriptor"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapUntypedPointersImageFunctionParam) { |
| AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderUntypedPointers); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_props.imageDescriptorSize); |
| |
| // TODO - vkt::DescriptorHeap needs to be fixed to make sure the heap memory is allocated to |
| // imageDescriptorAlignment |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "issues with alignment"; |
| } |
| |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0, 2); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = 0; |
| VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); |
| mapping_info.mappingCount = 1u; |
| mapping_info.pMappings = &mapping; |
| |
| char const* cs_source = R"( |
| OpCapability Shader |
| OpCapability SampledBuffer |
| OpCapability UntypedPointersKHR |
| OpCapability DescriptorHeapEXT |
| OpExtension "SPV_EXT_descriptor_heap" |
| OpExtension "SPV_KHR_untyped_pointers" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %2 "main" %3 %4 %5 |
| OpExecutionMode %2 LocalSize 1 1 1 |
| OpDecorate %3 BuiltIn ResourceHeapEXT |
| OpDecorateId %6 ArrayStrideIdEXT %7 |
| OpDecorate %4 Binding 0 |
| OpDecorate %4 DescriptorSet 0 |
| OpDecorate %8 Block |
| OpMemberDecorate %8 0 Offset 0 |
| OpDecorate %5 Binding 1 |
| OpDecorate %5 DescriptorSet 0 |
| %9 = OpTypeVoid |
| %10 = OpTypeFunction %9 |
| %11 = OpTypeInt 32 0 |
| %12 = OpTypeImage %11 Buffer 0 0 0 1 Unknown |
| %13 = OpTypePointer UniformConstant %12 |
| %14 = OpTypeUntypedPointerKHR UniformConstant |
| %15 = OpTypeFunction %11 %14 |
| %16 = OpConstant %11 0 |
| %17 = OpTypeVector %11 4 |
| %18 = OpTypeVector %11 2 |
| %3 = OpUntypedVariableKHR %14 UniformConstant |
| %7 = OpConstantSizeOfEXT %11 %12 |
| %6 = OpTypeRuntimeArray %12 |
| %19 = OpTypePointer Function %11 |
| %4 = OpVariable %13 UniformConstant |
| %20 = OpConstant %11 1 |
| %8 = OpTypeStruct %18 |
| %21 = OpTypePointer StorageBuffer %8 |
| %5 = OpVariable %21 StorageBuffer |
| %22 = OpTypePointer StorageBuffer %18 |
| %23 = OpTypeVector %11 3 |
| %24 = OpConstantComposite %23 %20 %20 %20 |
| %25 = OpFunction %11 None %15 |
| %26 = OpFunctionParameter %14 |
| %27 = OpLabel |
| %28 = OpLoad %12 %26 |
| %29 = OpImageFetch %17 %28 %16 ZeroExtend |
| %30 = OpCompositeExtract %11 %29 0 |
| OpReturnValue %30 |
| OpFunctionEnd |
| %2 = OpFunction %9 None %10 |
| %31 = OpLabel |
| %32 = OpUntypedAccessChainKHR %14 %6 %3 %16 |
| %33 = OpUntypedAccessChainKHR %14 %12 %4 |
| %34 = OpFunctionCall %11 %25 %32 |
| %35 = OpFunctionCall %11 %25 %33 |
| %36 = OpCompositeConstruct %18 %34 %35 |
| %37 = OpAccessChain %22 %5 %16 |
| OpStore %37 %36 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| vkt::HeapComputePipeline pipe(*m_device, cs_source, SPV_ENV_VULKAN_1_2, &mapping_info, SPV_SOURCE_ASM); |
| |
| m_command_buffer.Begin(); |
| desc_heap.BindResourceHeap(m_command_buffer); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredInfo("(is a function argument)"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeGpuDump, DescriptorHeapReservedRangeRuntimeArray) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12786"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredFeature(vkt::Feature::runtimeDescriptorArray); |
| RETURN_IF_SKIP(InitDescriptorHeap()); |
| |
| VkDeviceSize heap_size = heap_props.bufferDescriptorSize * 4; |
| |
| // For devices with no reserved range, add a bit after regardless |
| const bool no_reserved_range = heap_props.minResourceHeapReservedRange == 0; |
| if (no_reserved_range) { |
| heap_size += heap_props.bufferDescriptorSize; |
| } |
| vkt::DescriptorHeap desc_heap(*this); |
| desc_heap.CreateResourceHeap(heap_size); |
| |
| const char* cs_source = R"glsl( |
| #version 450 |
| #extension GL_EXT_nonuniform_qualifier : enable |
| layout (set = 0, binding = 0) buffer SSBO { |
| uint data; |
| } buffers[]; |
| |
| void main() { |
| uint tid = gl_GlobalInvocationID.x; |
| buffers[tid].data = 0; |
| } |
| )glsl"; |
| VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); |
| mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; |
| mapping.sourceData.constantOffset.heapOffset = 0; |
| mapping.sourceData.constantOffset.heapArrayStride = (uint32_t)heap_props.bufferDescriptorSize; |
| 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(); |
| |
| VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); |
| bind_resource_info.heapRange = desc_heap.resource_heap_.AddressRange(); |
| bind_resource_info.reservedRangeOffset = desc_heap.GetResourceHeapReservedRangeOffset(); |
| bind_resource_info.reservedRangeSize = heap_props.minResourceHeapReservedRange; |
| if (no_reserved_range) { |
| bind_resource_info.reservedRangeOffset -= heap_props.bufferDescriptorSize; |
| bind_resource_info.reservedRangeSize = heap_props.bufferDescriptorSize; |
| } |
| vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| m_errorMonitor->SetDesiredInfo("[INFO] RESERVED RANGE"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |