diff --git a/BUILD.gn b/BUILD.gn index b0229f93143..c592bc61eff 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -191,6 +191,8 @@ vvl_sources = [ "layers/gpu/spirv/bindless_descriptor_pass.h", "layers/gpu/spirv/non_bindless_oob_buffer_pass.cpp", "layers/gpu/spirv/non_bindless_oob_buffer_pass.h", + "layers/gpu/spirv/non_bindless_oob_texel_buffer_pass.cpp", + "layers/gpu/spirv/non_bindless_oob_texel_buffer_pass.h", "layers/gpu/spirv/buffer_device_address_pass.cpp", "layers/gpu/spirv/buffer_device_address_pass.h", "layers/gpu/spirv/function_basic_block.cpp", @@ -356,6 +358,8 @@ vvl_sources = [ "layers/vulkan/generated/instrumentation_bindless_descriptor_comp.h", "layers/vulkan/generated/instrumentation_non_bindless_oob_buffer_comp.cpp", "layers/vulkan/generated/instrumentation_non_bindless_oob_buffer_comp.h", + "layers/vulkan/generated/instrumentation_non_bindless_oob_texel_buffer_comp.cpp", + "layers/vulkan/generated/instrumentation_non_bindless_oob_texel_buffer_comp.h", "layers/vulkan/generated/instrumentation_buffer_device_address_comp.cpp", "layers/vulkan/generated/instrumentation_buffer_device_address_comp.h", "layers/vulkan/generated/instrumentation_ray_query_comp.cpp", diff --git a/layers/gpu/instrumentation/gpu_shader_instrumentor.cpp b/layers/gpu/instrumentation/gpu_shader_instrumentor.cpp index eca217c75cc..a80f1d32b73 100644 --- a/layers/gpu/instrumentation/gpu_shader_instrumentor.cpp +++ b/layers/gpu/instrumentation/gpu_shader_instrumentor.cpp @@ -1204,6 +1204,7 @@ bool GpuShaderInstrumentor::InstrumentShader(const vvl::span &in if (shader_instrumentation.bindless_descriptor) { modified |= module.RunPassBindlessDescriptor(); modified |= module.RunPassNonBindlessOOBBuffer(); + modified |= module.RunPassNonBindlessOOBTexelBuffer(); } if (shader_instrumentation.buffer_device_address) { diff --git a/layers/gpu/instrumentation/gpuav_instrumentation.cpp b/layers/gpu/instrumentation/gpuav_instrumentation.cpp index c664f32b827..60440834223 100644 --- a/layers/gpu/instrumentation/gpuav_instrumentation.cpp +++ b/layers/gpu/instrumentation/gpuav_instrumentation.cpp @@ -364,6 +364,32 @@ bool LogMessageInstNonBindlessOOB(Validator &gpuav, const uint32_t *error_record } } break; + case kErrorSubCodeNonBindlessOOBTexelBufferArrays: { + const uint32_t desc_array_size = error_record[kInstNonBindlessOOBParamOffset0]; + strm << " access out of bounds. The descriptor texel buffer array is " << desc_array_size + << " large, but as accessed at index [" << desc_index << "]"; + out_vuid_msg = "UNASSIGNED-Descriptor Texel Buffer index out of bounds"; + } break; + + case kErrorSubCodeNonBindlessOOBTexelBufferBounds: { + const auto *binding_state = descriptor_sets[set_num].state->GetBinding(binding_num); + const vvl::BufferView *buffer_view_state = + static_cast(binding_state)->descriptors[desc_index].GetBufferViewState(); + assert(buffer_view_state); + const uint32_t byte_offset = error_record[kInstNonBindlessOOBParamOffset0]; + const uint32_t resource_size = error_record[kInstNonBindlessOOBParamOffset1]; + + strm << " access out of bounds. The descriptor texel buffer (" << gpuav.FormatHandle(buffer_view_state->Handle()) + << ") size is " << resource_size << " texels and the highest out of bounds access was at [" << byte_offset + << "] bytes"; + + if (binding_state->type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) { + out_vuid_msg = uses_shader_object ? vuid.uniform_access_oob_08612 : vuid.uniform_access_oob_06935; + } else { + out_vuid_msg = uses_shader_object ? vuid.storage_access_oob_08613 : vuid.storage_access_oob_06936; + } + } break; + default: error_found = false; out_oob_access = false; diff --git a/layers/gpu/shaders/gpu_error_codes.h b/layers/gpu/shaders/gpu_error_codes.h index 9d99fb16201..17fc7615559 100644 --- a/layers/gpu/shaders/gpu_error_codes.h +++ b/layers/gpu/shaders/gpu_error_codes.h @@ -52,6 +52,9 @@ const int kErrorSubCodeBindlessDescriptorNullPointer = 5; // Buffers const int kErrorSubCodeNonBindlessOOBBufferArrays = 1; const int kErrorSubCodeNonBindlessOOBBufferBounds = 2; +// Texel Buffers +const int kErrorSubCodeNonBindlessOOBTexelBufferArrays = 3; +const int kErrorSubCodeNonBindlessOOBTexelBufferBounds = 4; // Buffer Device Address // diff --git a/layers/gpu/shaders/instrumentation/non_bindless_oob_texel_buffer.comp b/layers/gpu/shaders/instrumentation/non_bindless_oob_texel_buffer.comp new file mode 100644 index 00000000000..56e1437a2f6 --- /dev/null +++ b/layers/gpu/shaders/instrumentation/non_bindless_oob_texel_buffer.comp @@ -0,0 +1,138 @@ +// Copyright (c) 2024 The Khronos Group Inc. +// Copyright (c) 2024 Valve Corporation +// Copyright (c) 2024 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 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// NOTE: This file doesn't contain any entrypoints and should be compiled with then new --no-link option for glslang + +#version 450 +#extension GL_GOOGLE_include_directive : enable +#extension GL_EXT_buffer_reference : require +#extension GL_EXT_buffer_reference_uvec2 : require +#if defined(GL_ARB_gpu_shader_int64) +#extension GL_ARB_gpu_shader_int64 : require +#else +#error No extension available for 64-bit integers. +#endif + +#include "gpu_error_header.h" +#include "gpu_shaders_constants.h" +#include "common_descriptor_sets.h" + +layout(buffer_reference, buffer_reference_align = 8, std430) buffer DescriptorLayoutData { + // BindingLayout[0] + uint num_bindings; + uint pad; // always zero, used to keep things aligned + + // BindingLayout[1] - BindingLayout[N] + // struct glsl::BindingLayout { + // x: count + // y: state_start + // } + uvec2 data[]; +}; + +layout(buffer_reference, buffer_reference_align = 8, std430) buffer DescriptorSetInData { + // struct glsl::DescriptorState { + // x: id + // y: extra data depending on the descriptor type + // } + uvec2 data[]; +}; + +layout(buffer_reference, buffer_reference_align = 8, std430) buffer GlobalState { + // Maps to DescriptorHeap and used to detect if descriptor is still valid on CPU + uint data[]; +}; + +struct DescriptorSetRecord { + DescriptorLayoutData layout_data; + DescriptorSetInData in_data; + uvec2 out_data; // unused BDA pointer +}; + +layout(set = kInstDefaultDescriptorSet, binding = kBindingInstBindlessDescriptor, std430) buffer BindlessStateBuffer { + GlobalState global_state; + DescriptorSetRecord desc_sets[kDebugInputBindlessMaxDescSets]; +} bindless_state_buffer; + +// TODO - This currently the almost exact same code as inst_non_bindless_oob_buffer +// We do not want to waste time deciding which descriptor type it is inside the shader. +// While this is some code duplication, it keeps things seperated for non-bindlesss everywhere else +bool inst_non_bindless_oob_texel_buffer(const uint inst_num, const uvec4 stage_info, const uint desc_array_size, + const uint desc_set, const uint binding, const uint desc_index, const uint byte_offset) { + uint error = 0u; + uint param_0 = 0u; + uint param_1 = 0u; + do { + // For non-array this should hopefully optimized out as "if (0 > 1)" + if (desc_index > desc_array_size) { + error = kErrorSubCodeNonBindlessOOBTexelBufferArrays; + param_0 = desc_array_size; + break; + } + + DescriptorLayoutData layout_data = bindless_state_buffer.desc_sets[desc_set].layout_data; + uvec2 binding_state = layout_data.data[binding]; + + DescriptorSetInData in_data = bindless_state_buffer.desc_sets[desc_set].in_data; + + uint state_index = binding_state.y + desc_index; + + // check that the offset is in bounds + uint resource_size = in_data.data[state_index].y; + if (byte_offset >= resource_size) { + error = kErrorSubCodeNonBindlessOOBTexelBufferBounds; + param_0 = byte_offset; + param_1 = resource_size; + break; + } + } while (false); + + if (0u != error) { + + const uint cmd_id = inst_cmd_resource_index_buffer.index[0]; + const uint cmd_errors_count = atomicAdd(inst_cmd_errors_count_buffer.errors_count[cmd_id], 1); + const bool max_cmd_errors_count_reached = cmd_errors_count >= kMaxErrorsPerCmd; + + if (max_cmd_errors_count_reached) return false; + + uint write_pos = atomicAdd(inst_errors_buffer.written_count, kErrorRecordSize); + const bool errors_buffer_not_filled = (write_pos + kErrorRecordSize) <= uint(inst_errors_buffer.data.length()); + + if (errors_buffer_not_filled) { + inst_errors_buffer.data[write_pos + kHeaderErrorRecordSizeOffset] = kErrorRecordSize; + inst_errors_buffer.data[write_pos + kHeaderShaderIdOffset] = kLinkShaderId; + inst_errors_buffer.data[write_pos + kHeaderInstructionIdOffset] = inst_num; + inst_errors_buffer.data[write_pos + kHeaderStageIdOffset] = stage_info.x; + inst_errors_buffer.data[write_pos + kHeaderStageInfoOffset_0] = stage_info.y; + inst_errors_buffer.data[write_pos + kHeaderStageInfoOffset_1] = stage_info.z; + inst_errors_buffer.data[write_pos + kHeaderStageInfoOffset_2] = stage_info.w; + + inst_errors_buffer.data[write_pos + kHeaderErrorGroupOffset] = kErrorGroupInstNonBindlessOOB; + inst_errors_buffer.data[write_pos + kHeaderErrorSubCodeOffset] = error; + + inst_errors_buffer.data[write_pos + kHeaderActionIdOffset] = inst_action_index_buffer.index[0]; + inst_errors_buffer.data[write_pos + kHeaderCommandResourceIdOffset] = inst_cmd_resource_index_buffer.index[0]; + + inst_errors_buffer.data[write_pos + kInstBindlessDescSetOffset] = desc_set; + inst_errors_buffer.data[write_pos + kInstBindlessDescBindingOffset] = binding; + inst_errors_buffer.data[write_pos + kInstBindlessDescIndexOffset] = desc_index; + inst_errors_buffer.data[write_pos + kInstBindlessCustomOffset_0] = param_0; + inst_errors_buffer.data[write_pos + kInstBindlessCustomOffset_1] = param_1; + } + return false; + } + return true; +} \ No newline at end of file diff --git a/layers/gpu/spirv/CMakeLists.txt b/layers/gpu/spirv/CMakeLists.txt index 1c862eb6679..0e514e7588e 100644 --- a/layers/gpu/spirv/CMakeLists.txt +++ b/layers/gpu/spirv/CMakeLists.txt @@ -21,6 +21,8 @@ target_sources(gpu_av_spirv PRIVATE bindless_descriptor_pass.cpp non_bindless_oob_buffer_pass.h non_bindless_oob_buffer_pass.cpp + non_bindless_oob_texel_buffer_pass.h + non_bindless_oob_texel_buffer_pass.cpp buffer_device_address_pass.h buffer_device_address_pass.cpp ray_query_pass.h @@ -50,6 +52,8 @@ target_sources(gpu_av_spirv PRIVATE ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/instrumentation_bindless_descriptor_comp.cpp ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/instrumentation_non_bindless_oob_buffer_comp.h ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/instrumentation_non_bindless_oob_buffer_comp.cpp + ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/instrumentation_non_bindless_oob_texel_buffer_comp.h + ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/instrumentation_non_bindless_oob_texel_buffer_comp.cpp ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/instrumentation_buffer_device_address_comp.h ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/instrumentation_buffer_device_address_comp.cpp ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/instrumentation_ray_query_comp.h diff --git a/layers/gpu/spirv/bindless_descriptor_pass.cpp b/layers/gpu/spirv/bindless_descriptor_pass.cpp index 09d4e94d845..4be4f9ec980 100644 --- a/layers/gpu/spirv/bindless_descriptor_pass.cpp +++ b/layers/gpu/spirv/bindless_descriptor_pass.cpp @@ -186,6 +186,9 @@ bool BindlessDescriptorPass::AnalyzeInstruction(const Function& function, const } } else { + // TODO - Once all non-bindless passes are added, this check can be places at top of Run() + if (!module_.has_bindless_descriptors_ && opcode == spv::OpImageFetch) return false; + // Reference is not load or store, so ifi it isn't a image-based reference, move on const uint32_t image_word = OpcodeImageAccessPosition(opcode); if (image_word == 0) { diff --git a/layers/gpu/spirv/link.h b/layers/gpu/spirv/link.h index 5b061403245..d11e0d39485 100644 --- a/layers/gpu/spirv/link.h +++ b/layers/gpu/spirv/link.h @@ -24,6 +24,7 @@ enum class LinkFunctions { inst_buffer_device_address, inst_bindless_descriptor, inst_non_bindless_oob_buffer, + inst_non_bindless_oob_texel_buffer, inst_ray_query, }; diff --git a/layers/gpu/spirv/module.cpp b/layers/gpu/spirv/module.cpp index aaaf2838199..a98b3afdb95 100644 --- a/layers/gpu/spirv/module.cpp +++ b/layers/gpu/spirv/module.cpp @@ -21,6 +21,7 @@ #include "buffer_device_address_pass.h" #include "bindless_descriptor_pass.h" #include "non_bindless_oob_buffer_pass.h" +#include "non_bindless_oob_texel_buffer_pass.h" #include "ray_query_pass.h" #include "debug_printf_pass.h" @@ -293,6 +294,15 @@ bool Module::RunPassNonBindlessOOBBuffer() { return changed; } +bool Module::RunPassNonBindlessOOBTexelBuffer() { + NonBindlessOOBTexelBufferPass pass(*this); + const bool changed = pass.Run(); + if (print_debug_info_) { + pass.PrintDebugInfo(); + } + return changed; +} + bool Module::RunPassBufferDeviceAddress() { BufferDeviceAddressPass pass(*this); const bool changed = pass.Run(); @@ -393,7 +403,7 @@ void Module::LinkFunction(const LinkInfo& info) { // track the incoming SSA IDs with what they are in the module // < old_id, new_id > vvl::unordered_map id_swap_map; - const uint32_t function_type_id = TakeNextId(); + uint32_t function_type_id = 0; // Track all decorations and add after when have full id_swap_map InstructionList decorations; @@ -493,17 +503,31 @@ void Module::LinkFunction(const LinkInfo& info) { type_manager_.AddType(std::move(new_inst), spv_type); break; } - case SpvType::kStruct: - case SpvType::kFunction: { + case SpvType::kStruct: { // For OpTypeStruct, we just add it regardless since low chance to find for the amount of time to search all - // struct (which there can be quite a bit of) For OpTypeFunction, we will only have one and custom function - // likely won't match anything neither - type_id = (spv_type == SpvType::kFunction) ? function_type_id : TakeNextId(); + // struct (which there can be quite a bit of) + type_id = TakeNextId(); new_inst->ReplaceResultId(type_id); new_inst->ReplaceLinkedId(id_swap_map); type_manager_.AddType(std::move(new_inst), spv_type).Id(); break; } + case SpvType::kFunction: { + // It is not valid to have duplicate OpTypeFunction and some linked in functions will have the same signature + new_inst->ReplaceLinkedId(id_swap_map); + // First swap out IDs so comparison will be the same + const Type* function_type = type_manager_.FindFunctionType(*new_inst.get()); + if (function_type) { + // Just reuse non-unique OpTypeFunction + function_type_id = function_type->Id(); + } else { + function_type_id = TakeNextId(); + type_id = function_type_id; + new_inst->ReplaceResultId(type_id); + type_manager_.AddType(std::move(new_inst), spv_type).Id(); + } + break; + } default: break; } diff --git a/layers/gpu/spirv/module.h b/layers/gpu/spirv/module.h index a96f1292c67..eea41cb968f 100644 --- a/layers/gpu/spirv/module.h +++ b/layers/gpu/spirv/module.h @@ -85,6 +85,7 @@ class Module { // Return true if code was instrumented bool RunPassBindlessDescriptor(); bool RunPassNonBindlessOOBBuffer(); + bool RunPassNonBindlessOOBTexelBuffer(); bool RunPassBufferDeviceAddress(); bool RunPassRayQuery(); bool RunPassDebugPrintf(uint32_t binding_slot = 0); diff --git a/layers/gpu/spirv/non_bindless_oob_buffer_pass.cpp b/layers/gpu/spirv/non_bindless_oob_buffer_pass.cpp index e7848381118..1fbc2665a65 100644 --- a/layers/gpu/spirv/non_bindless_oob_buffer_pass.cpp +++ b/layers/gpu/spirv/non_bindless_oob_buffer_pass.cpp @@ -82,7 +82,6 @@ void NonBindlessOOBBufferPass::Reset() { } bool NonBindlessOOBBufferPass::AnalyzeInstruction(const Function& function, const Instruction& inst) { - if (module_.has_bindless_descriptors_) return false; const uint32_t opcode = inst.Opcode(); if (opcode != spv::OpLoad && opcode != spv::OpStore) { @@ -175,6 +174,7 @@ void NonBindlessOOBBufferPass::PrintDebugInfo() { // Created own Run() because need to control finding the largest offset in a given block bool NonBindlessOOBBufferPass::Run() { + if (module_.has_bindless_descriptors_) return false; // Can safely loop function list as there is no injecting of new Functions until linking time for (const auto& function : module_.functions_) { for (auto block_it = function->blocks_.begin(); block_it != function->blocks_.end(); ++block_it) { diff --git a/layers/gpu/spirv/non_bindless_oob_texel_buffer_pass.cpp b/layers/gpu/spirv/non_bindless_oob_texel_buffer_pass.cpp new file mode 100644 index 00000000000..6020eed9850 --- /dev/null +++ b/layers/gpu/spirv/non_bindless_oob_texel_buffer_pass.cpp @@ -0,0 +1,234 @@ +/* Copyright (c) 2024 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "non_bindless_oob_texel_buffer_pass.h" +#include "module.h" +#include +#include + +#include "generated/instrumentation_non_bindless_oob_texel_buffer_comp.h" +#include "gpu/shaders/gpu_shaders_constants.h" + +namespace gpu { +namespace spirv { + +NonBindlessOOBTexelBufferPass::NonBindlessOOBTexelBufferPass(Module& module) : Pass(module) { module.use_bda_ = true; } + +static LinkInfo link_info = {instrumentation_non_bindless_oob_texel_buffer_comp, + instrumentation_non_bindless_oob_texel_buffer_comp_size, + LinkFunctions::inst_non_bindless_oob_texel_buffer, 0, "inst_non_bindless_oob_texel_buffer"}; + +// By appending the LinkInfo, it will attempt at linking stage to add the function. +uint32_t NonBindlessOOBTexelBufferPass::GetLinkFunctionId() { + if (link_function_id == 0) { + link_function_id = module_.TakeNextId(); + link_info.function_id = link_function_id; + module_.link_info_.push_back(link_info); + } + return link_function_id; +} + +uint32_t NonBindlessOOBTexelBufferPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, + const InjectionData& injection_data) { + assert(access_chain_inst_ && var_inst_); + const Constant& set_constant = module_.type_manager_.GetConstantUInt32(descriptor_set_); + const Constant& binding_constant = module_.type_manager_.GetConstantUInt32(descriptor_binding_); + const uint32_t descriptor_index_id = CastToUint32(descriptor_index_id_, block, inst_it); // might be int32 + + const uint32_t opcode = target_instruction_->Opcode(); + const uint32_t image_operand_position = OpcodeImageOperandsPosition(opcode); + if (target_instruction_->Length() > image_operand_position) { + const uint32_t image_operand_word = target_instruction_->Word(image_operand_position); + if ((image_operand_word & (spv::ImageOperandsConstOffsetMask | spv::ImageOperandsOffsetMask)) != 0) { + // TODO - Add support if there are image operands (like offset) + } + } + + // Use the imageFetch() parameter to decide the offset + // TODO - This assumes no depth/arrayed/ms from AnalyzeInstruction + descriptor_offset_id_ = CastToUint32(target_instruction_->Operand(1), block, inst_it); + + const uint32_t function_result = module_.TakeNextId(); + const uint32_t function_def = GetLinkFunctionId(); + const uint32_t bool_type = module_.type_manager_.GetTypeBool().Id(); + + block.CreateInstruction( + spv::OpFunctionCall, + {bool_type, function_result, function_def, injection_data.inst_position_id, injection_data.stage_info_id, + descriptor_array_size_id_, set_constant.Id(), binding_constant.Id(), descriptor_index_id, descriptor_offset_id_}, + inst_it); + + return function_result; +} + +void NonBindlessOOBTexelBufferPass::Reset() { + access_chain_inst_ = nullptr; + var_inst_ = nullptr; + target_instruction_ = nullptr; + descriptor_array_size_id_ = 0; + descriptor_set_ = 0; + descriptor_binding_ = 0; + descriptor_index_id_ = 0; + descriptor_offset_id_ = 0; +} + +bool NonBindlessOOBTexelBufferPass::AnalyzeInstruction(const Function& function, const Instruction& inst) { + const uint32_t opcode = inst.Opcode(); + + if (opcode != spv::OpImageFetch) { + return false; + } + const uint32_t image_word = OpcodeImageAccessPosition(opcode); + + image_inst_ = function.FindInstruction(inst.Word(image_word)); + if (!image_inst_) return false; + const Type* image_type = module_.type_manager_.FindTypeById(image_inst_->TypeId()); + if (!image_type) return false; + + const uint32_t dim = image_type->inst_.Operand(1); + if (dim != spv::DimBuffer) { + return false; // seems like a spirv-val issue, but be safe and just ignore + } + const uint32_t depth = image_type->inst_.Operand(2); + const uint32_t arrayed = image_type->inst_.Operand(3); + const uint32_t ms = image_type->inst_.Operand(4); + if (depth != 0 || arrayed != 0 || ms != 0) { + // TODO - Currently don't support caculating these for getting the OOB offset, so not worst continuing + return false; + } + + // walk down to get the actual load + const Instruction* load_inst = image_inst_; + while (load_inst && (load_inst->Opcode() == spv::OpSampledImage || load_inst->Opcode() == spv::OpImage || + load_inst->Opcode() == spv::OpCopyObject)) { + load_inst = function.FindInstruction(load_inst->Operand(0)); + } + if (!load_inst || load_inst->Opcode() != spv::OpLoad) { + return false; // TODO: Handle additional possibilities? + } + + var_inst_ = function.FindInstruction(load_inst->Operand(0)); + if (!var_inst_) { + // can be a global variable + const Variable* global_var = module_.type_manager_.FindVariableById(load_inst->Operand(0)); + var_inst_ = global_var ? &global_var->inst_ : nullptr; + } + if (!var_inst_ || (var_inst_->Opcode() != spv::OpAccessChain && var_inst_->Opcode() != spv::OpVariable)) { + return false; + } + + // If OpVariable, access_chain_inst_ is never checked because it should be a direct image access + access_chain_inst_ = var_inst_; + + if (var_inst_->Opcode() == spv::OpAccessChain) { + descriptor_index_id_ = var_inst_->Operand(1); + + if (var_inst_->Length() > 5) { + module_.InternalError("NonBindlessOOBTexelBufferPass", + "OpAccessChain has more than 1 indexes. 2D Texel Buffers not supported"); + return false; + } + + const Variable* variable = module_.type_manager_.FindVariableById(var_inst_->Operand(0)); + if (!variable) { + module_.InternalError("NonBindlessOOBTexelBufferPass", "OpAccessChain base is not a variable"); + return false; + } + var_inst_ = &variable->inst_; + + const Type* pointer_type = variable->PointerType(module_.type_manager_); + if (pointer_type->inst_.Opcode() == spv::OpTypeRuntimeArray) { + return false; // Currently we mark these are "bindless" + } else if (pointer_type->inst_.Opcode() == spv::OpTypeArray) { + const Constant* array_size_const = module_.type_manager_.FindConstantById(pointer_type->inst_.Operand(1)); + if (!array_size_const) { + return false; // TODO - Handle Spec Constants here + } + descriptor_array_size_id_ = array_size_const->Id(); + } else { + module_.InternalError("NonBindlessOOBTexelBufferPass", "OpAccessChain has no array in it"); + return false; + } + + } else { + // There is no array of this descriptor, so we essentially have an array of 1 + descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id(); + descriptor_array_size_id_ = module_.type_manager_.GetConstantUInt32(1).Id(); + } + + uint32_t variable_id = var_inst_->ResultId(); + for (const auto& annotation : module_.annotations_) { + if (annotation->Opcode() == spv::OpDecorate && annotation->Word(1) == variable_id) { + if (annotation->Word(2) == spv::DecorationDescriptorSet) { + descriptor_set_ = annotation->Word(3); + } else if (annotation->Word(2) == spv::DecorationBinding) { + descriptor_binding_ = annotation->Word(3); + } + } + } + + if (descriptor_set_ >= gpuav::glsl::kDebugInputBindlessMaxDescSets) { + module_.InternalWarning("NonBindlessOOBTexelBufferPass", "Tried to use a descriptor slot over the current max limit"); + return false; + } + + // Save information to be used to make the Function + target_instruction_ = &inst; + + return true; +} + +void NonBindlessOOBTexelBufferPass::PrintDebugInfo() { + std::cout << "NonBindlessOOBTexelBufferPass\n\tinstrumentation count: " << instrumented_count_ << '\n'; +} + +// Created own Run() because need to control finding the largest offset in a given block +bool NonBindlessOOBTexelBufferPass::Run() { + if (module_.has_bindless_descriptors_) return false; + // Can safely loop function list as there is no injecting of new Functions until linking time + for (const auto& function : module_.functions_) { + for (auto block_it = function->blocks_.begin(); block_it != function->blocks_.end(); ++block_it) { + if ((*block_it)->loop_header_) { + continue; // Currently can't properly handle injecting CFG logic into a loop header block + } + auto& block_instructions = (*block_it)->instructions_; + for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) { + // Every instruction is analyzed by the specific pass and lets us know if we need to inject a function or not + if (!AnalyzeInstruction(*function, *(inst_it->get()))) continue; + + if (module_.max_instrumented_count_ != 0 && instrumented_count_ >= module_.max_instrumented_count_) { + return true; // hit limit + } + instrumented_count_++; + + // Add any debug information to pass into the function call + InjectionData injection_data; + injection_data.stage_info_id = GetStageInfo(*function, block_it, inst_it); + const uint32_t inst_position = target_instruction_->position_index_; + auto inst_position_constant = module_.type_manager_.CreateConstantUInt32(inst_position); + injection_data.inst_position_id = inst_position_constant.Id(); + + // inst_it is updated to the instruction after the new function call, it will not add/remove any Blocks + CreateFunctionCall(**block_it, &inst_it, injection_data); + Reset(); + } + } + } + + return instrumented_count_ != 0; +} + +} // namespace spirv +} // namespace gpu \ No newline at end of file diff --git a/layers/gpu/spirv/non_bindless_oob_texel_buffer_pass.h b/layers/gpu/spirv/non_bindless_oob_texel_buffer_pass.h new file mode 100644 index 00000000000..3e32deaec1b --- /dev/null +++ b/layers/gpu/spirv/non_bindless_oob_texel_buffer_pass.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2024 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include "pass.h" + +namespace gpu { +namespace spirv { + +// Will make sure Texel Buffers that are non bindless are not OOB Uses robustBufferAccess to ensure if we +// are OOB that it won't crash and we will return the error safely +class NonBindlessOOBTexelBufferPass : public Pass { + public: + NonBindlessOOBTexelBufferPass(Module& module); + void PrintDebugInfo() final; + bool Run() final; + + private: + bool AnalyzeInstruction(const Function& function, const Instruction& inst); + uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data); + void Reset() final; + + uint32_t link_function_id = 0; + uint32_t GetLinkFunctionId(); + + const Instruction* access_chain_inst_ = nullptr; + const Instruction* var_inst_ = nullptr; + const Instruction* image_inst_ = nullptr; + + uint32_t descriptor_array_size_id_ = 0; // the size of the descriptor array (size is 1 if no array) + uint32_t descriptor_set_ = 0; + uint32_t descriptor_binding_ = 0; + uint32_t descriptor_index_id_ = 0; // index input the descriptor array + uint32_t descriptor_offset_id_ = 0; +}; + +} // namespace spirv +} // namespace gpu \ No newline at end of file diff --git a/layers/gpu/spirv/type_manager.cpp b/layers/gpu/spirv/type_manager.cpp index b61638989a5..b5022c3decb 100644 --- a/layers/gpu/spirv/type_manager.cpp +++ b/layers/gpu/spirv/type_manager.cpp @@ -113,6 +113,27 @@ const Type* TypeManager::FindTypeById(uint32_t id) const { return (type == id_to_type_.end()) ? nullptr : type->second.get(); } +const Type* TypeManager::FindFunctionType(const Instruction& inst) const { + const uint32_t inst_length = inst.Length(); + for (const auto& type : function_types_) { + if (type->inst_.Length() != inst_length) { + continue; + } + // Start at the Result Type ID (skip ResultID and the base word) + bool found = true; + for (uint32_t i = 2; i < inst_length; i++) { + if (type->inst_.Word(i) != inst.Word(i)) { + found = false; + break; + } + } + if (found) { + return type; + } + } + return nullptr; +} + const Type& TypeManager::GetTypeVoid() { if (void_type) { return *void_type; diff --git a/layers/gpu/spirv/type_manager.h b/layers/gpu/spirv/type_manager.h index 5777446b3d0..ce8511820bd 100644 --- a/layers/gpu/spirv/type_manager.h +++ b/layers/gpu/spirv/type_manager.h @@ -94,6 +94,7 @@ class TypeManager { const Type& AddType(std::unique_ptr new_inst, SpvType spv_type); const Type* FindTypeById(uint32_t id) const; + const Type* FindFunctionType(const Instruction& inst) const; // There shouldn't be a case where we need to query for a specific type, but then not add it if not found. const Type& GetTypeVoid(); const Type& GetTypeBool(); diff --git a/layers/vulkan/generated/instrumentation_non_bindless_oob_texel_buffer_comp.cpp b/layers/vulkan/generated/instrumentation_non_bindless_oob_texel_buffer_comp.cpp new file mode 100644 index 00000000000..9d85efcc173 --- /dev/null +++ b/layers/vulkan/generated/instrumentation_non_bindless_oob_texel_buffer_comp.cpp @@ -0,0 +1,167 @@ +// *** THIS FILE IS GENERATED - DO NOT EDIT *** +// See generate_spirv.py for modifications + +/*************************************************************************** + * + * Copyright (c) 2021-2024 The Khronos Group Inc. + * Copyright (c) 2021-2024 Valve Corporation + * Copyright (c) 2021-2024 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +#include "instrumentation_non_bindless_oob_texel_buffer_comp.h" + +// To view SPIR-V, copy contents of array and paste in https://www.khronos.org/spir/visualizer/ +[[maybe_unused]] const uint32_t instrumentation_non_bindless_oob_texel_buffer_comp_size = 1374; +[[maybe_unused]] const uint32_t instrumentation_non_bindless_oob_texel_buffer_comp[1374] = { + 0x07230203, 0x00010300, 0x0008000b, 0x000000d0, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000005, 0x00020011, + 0x000014e3, 0x0009000a, 0x5f565053, 0x5f52484b, 0x73796870, 0x6c616369, 0x6f74735f, 0x65676172, 0x6675625f, 0x00726566, + 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x000014e4, 0x00000001, 0x00030003, + 0x00000002, 0x000001c2, 0x00070004, 0x415f4c47, 0x675f4252, 0x735f7570, 0x65646168, 0x6e695f72, 0x00343674, 0x00070004, + 0x455f4c47, 0x625f5458, 0x65666675, 0x65725f72, 0x65726566, 0x0065636e, 0x00090004, 0x455f4c47, 0x625f5458, 0x65666675, + 0x65725f72, 0x65726566, 0x5f65636e, 0x63657675, 0x00000032, 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, + 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, + 0x69645f65, 0x74636572, 0x00657669, 0x00110005, 0x0000000d, 0x74736e69, 0x6e6f6e5f, 0x6e69625f, 0x73656c64, 0x6f6f5f73, + 0x65745f62, 0x5f6c6578, 0x66667562, 0x75287265, 0x75763b31, 0x31753b34, 0x3b31753b, 0x753b3175, 0x31753b31, 0x0000003b, + 0x00050005, 0x00000006, 0x74736e69, 0x6d756e5f, 0x00000000, 0x00050005, 0x00000007, 0x67617473, 0x6e695f65, 0x00006f66, + 0x00060005, 0x00000008, 0x63736564, 0x7272615f, 0x735f7961, 0x00657a69, 0x00050005, 0x00000009, 0x63736564, 0x7465735f, + 0x00000000, 0x00040005, 0x0000000a, 0x646e6962, 0x00676e69, 0x00050005, 0x0000000b, 0x63736564, 0x646e695f, 0x00007865, + 0x00050005, 0x0000000c, 0x65747962, 0x66666f5f, 0x00746573, 0x00040005, 0x00000010, 0x6f727265, 0x00000072, 0x00040005, + 0x00000012, 0x61726170, 0x00305f6d, 0x00040005, 0x00000013, 0x61726170, 0x00315f6d, 0x00080005, 0x00000020, 0x63736544, + 0x74706972, 0x614c726f, 0x74756f79, 0x61746144, 0x00000000, 0x00070006, 0x00000020, 0x00000000, 0x5f6d756e, 0x646e6962, + 0x73676e69, 0x00000000, 0x00040006, 0x00000020, 0x00000001, 0x00646170, 0x00050006, 0x00000020, 0x00000002, 0x61746164, + 0x00000000, 0x00070005, 0x00000025, 0x63736544, 0x74706972, 0x6553726f, 0x63655274, 0x0064726f, 0x00060006, 0x00000025, + 0x00000000, 0x6f79616c, 0x645f7475, 0x00617461, 0x00050006, 0x00000025, 0x00000001, 0x645f6e69, 0x00617461, 0x00060006, + 0x00000025, 0x00000002, 0x5f74756f, 0x61746164, 0x00000000, 0x00070005, 0x00000027, 0x63736544, 0x74706972, 0x6553726f, + 0x446e4974, 0x00617461, 0x00050006, 0x00000027, 0x00000000, 0x61746164, 0x00000000, 0x00070005, 0x0000002a, 0x646e6942, + 0x7373656c, 0x74617453, 0x66754265, 0x00726566, 0x00070006, 0x0000002a, 0x00000000, 0x626f6c67, 0x735f6c61, 0x65746174, + 0x00000000, 0x00060006, 0x0000002a, 0x00000001, 0x63736564, 0x7465735f, 0x00000073, 0x00050005, 0x0000002c, 0x626f6c47, + 0x74536c61, 0x00657461, 0x00050006, 0x0000002c, 0x00000000, 0x61746164, 0x00000000, 0x00080005, 0x0000002e, 0x646e6962, + 0x7373656c, 0x6174735f, 0x625f6574, 0x65666675, 0x00000072, 0x00060005, 0x00000036, 0x646e6962, 0x5f676e69, 0x74617473, + 0x00000065, 0x00080005, 0x0000005a, 0x52646d43, 0x756f7365, 0x49656372, 0x7865646e, 0x66667542, 0x00007265, 0x00050006, + 0x0000005a, 0x00000000, 0x65646e69, 0x00000078, 0x000a0005, 0x0000005c, 0x74736e69, 0x646d635f, 0x7365725f, 0x6372756f, + 0x6e695f65, 0x5f786564, 0x66667562, 0x00007265, 0x00080005, 0x00000062, 0x45646d43, 0x726f7272, 0x756f4373, 0x7542746e, + 0x72656666, 0x00000000, 0x00070006, 0x00000062, 0x00000000, 0x6f727265, 0x635f7372, 0x746e756f, 0x00000000, 0x000a0005, + 0x00000064, 0x74736e69, 0x646d635f, 0x7272655f, 0x5f73726f, 0x6e756f63, 0x75625f74, 0x72656666, 0x00000000, 0x00060005, + 0x00000073, 0x7074754f, 0x75427475, 0x72656666, 0x00000000, 0x00050006, 0x00000073, 0x00000000, 0x67616c66, 0x00000073, + 0x00070006, 0x00000073, 0x00000001, 0x74697277, 0x5f6e6574, 0x6e756f63, 0x00000074, 0x00050006, 0x00000073, 0x00000002, + 0x61746164, 0x00000000, 0x00070005, 0x00000075, 0x74736e69, 0x7272655f, 0x5f73726f, 0x66667562, 0x00007265, 0x00070005, + 0x000000ad, 0x69746341, 0x6e496e6f, 0x42786564, 0x65666675, 0x00000072, 0x00050006, 0x000000ad, 0x00000000, 0x65646e69, + 0x00000078, 0x00090005, 0x000000af, 0x74736e69, 0x7463615f, 0x5f6e6f69, 0x65646e69, 0x75625f78, 0x72656666, 0x00000000, + 0x000d0047, 0x0000000d, 0x00000029, 0x74736e69, 0x6e6f6e5f, 0x6e69625f, 0x73656c64, 0x6f6f5f73, 0x65745f62, 0x5f6c6578, + 0x66667562, 0x00007265, 0x00000000, 0x00040047, 0x0000001f, 0x00000006, 0x00000008, 0x00030047, 0x00000020, 0x00000002, + 0x00050048, 0x00000020, 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x00000020, 0x00000001, 0x00000023, 0x00000004, + 0x00050048, 0x00000020, 0x00000002, 0x00000023, 0x00000008, 0x00050048, 0x00000025, 0x00000000, 0x00000023, 0x00000000, + 0x00050048, 0x00000025, 0x00000001, 0x00000023, 0x00000008, 0x00050048, 0x00000025, 0x00000002, 0x00000023, 0x00000010, + 0x00040047, 0x00000026, 0x00000006, 0x00000008, 0x00030047, 0x00000027, 0x00000002, 0x00050048, 0x00000027, 0x00000000, + 0x00000023, 0x00000000, 0x00040047, 0x00000029, 0x00000006, 0x00000018, 0x00030047, 0x0000002a, 0x00000002, 0x00050048, + 0x0000002a, 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x0000002a, 0x00000001, 0x00000023, 0x00000008, 0x00040047, + 0x0000002b, 0x00000006, 0x00000004, 0x00030047, 0x0000002c, 0x00000002, 0x00050048, 0x0000002c, 0x00000000, 0x00000023, + 0x00000000, 0x00040047, 0x0000002e, 0x00000021, 0x00000001, 0x00040047, 0x0000002e, 0x00000022, 0x00000007, 0x00040047, + 0x00000059, 0x00000006, 0x00000004, 0x00030047, 0x0000005a, 0x00000002, 0x00050048, 0x0000005a, 0x00000000, 0x00000023, + 0x00000000, 0x00040047, 0x0000005c, 0x00000021, 0x00000004, 0x00040047, 0x0000005c, 0x00000022, 0x00000007, 0x00040047, + 0x00000061, 0x00000006, 0x00000004, 0x00030047, 0x00000062, 0x00000002, 0x00050048, 0x00000062, 0x00000000, 0x00000023, + 0x00000000, 0x00040047, 0x00000064, 0x00000021, 0x00000005, 0x00040047, 0x00000064, 0x00000022, 0x00000007, 0x00040047, + 0x00000072, 0x00000006, 0x00000004, 0x00030047, 0x00000073, 0x00000002, 0x00050048, 0x00000073, 0x00000000, 0x00000023, + 0x00000000, 0x00050048, 0x00000073, 0x00000001, 0x00000023, 0x00000004, 0x00050048, 0x00000073, 0x00000002, 0x00000023, + 0x00000008, 0x00040047, 0x00000075, 0x00000021, 0x00000000, 0x00040047, 0x00000075, 0x00000022, 0x00000007, 0x00040047, + 0x000000ac, 0x00000006, 0x00000004, 0x00030047, 0x000000ad, 0x00000002, 0x00050048, 0x000000ad, 0x00000000, 0x00000023, + 0x00000000, 0x00040047, 0x000000af, 0x00000021, 0x00000003, 0x00040047, 0x000000af, 0x00000022, 0x00000007, 0x00040015, + 0x00000002, 0x00000020, 0x00000000, 0x00040017, 0x00000003, 0x00000002, 0x00000004, 0x00020014, 0x00000004, 0x000a0021, + 0x00000005, 0x00000004, 0x00000002, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00040020, + 0x0000000f, 0x00000007, 0x00000002, 0x0004002b, 0x00000002, 0x00000011, 0x00000000, 0x0004002b, 0x00000002, 0x0000001b, + 0x00000003, 0x00030027, 0x0000001d, 0x000014e5, 0x00040017, 0x0000001e, 0x00000002, 0x00000002, 0x0003001d, 0x0000001f, + 0x0000001e, 0x0005001e, 0x00000020, 0x00000002, 0x00000002, 0x0000001f, 0x00040020, 0x0000001d, 0x000014e5, 0x00000020, + 0x00030027, 0x00000023, 0x000014e5, 0x00030027, 0x00000024, 0x000014e5, 0x0005001e, 0x00000025, 0x0000001d, 0x00000024, + 0x0000001e, 0x0003001d, 0x00000026, 0x0000001e, 0x0003001e, 0x00000027, 0x00000026, 0x00040020, 0x00000024, 0x000014e5, + 0x00000027, 0x0004002b, 0x00000002, 0x00000028, 0x00000020, 0x0004001c, 0x00000029, 0x00000025, 0x00000028, 0x0004001e, + 0x0000002a, 0x00000023, 0x00000029, 0x0003001d, 0x0000002b, 0x00000002, 0x0003001e, 0x0000002c, 0x0000002b, 0x00040020, + 0x00000023, 0x000014e5, 0x0000002c, 0x00040020, 0x0000002d, 0x0000000c, 0x0000002a, 0x0004003b, 0x0000002d, 0x0000002e, + 0x0000000c, 0x00040015, 0x0000002f, 0x00000020, 0x00000001, 0x0004002b, 0x0000002f, 0x00000030, 0x00000001, 0x0004002b, + 0x0000002f, 0x00000031, 0x00000000, 0x00040020, 0x00000032, 0x0000000c, 0x0000001d, 0x00040020, 0x00000035, 0x00000007, + 0x0000001e, 0x0004002b, 0x0000002f, 0x00000038, 0x00000002, 0x00040020, 0x00000039, 0x000014e5, 0x0000001e, 0x00040020, + 0x0000003e, 0x0000000c, 0x00000024, 0x0004002b, 0x00000002, 0x00000042, 0x00000001, 0x00040020, 0x00000049, 0x000014e5, + 0x00000002, 0x0004002b, 0x00000002, 0x00000050, 0x00000004, 0x0003002a, 0x00000004, 0x00000053, 0x0003001d, 0x00000059, + 0x00000002, 0x0003001e, 0x0000005a, 0x00000059, 0x00040020, 0x0000005b, 0x0000000c, 0x0000005a, 0x0004003b, 0x0000005b, + 0x0000005c, 0x0000000c, 0x00040020, 0x0000005d, 0x0000000c, 0x00000002, 0x0003001d, 0x00000061, 0x00000002, 0x0003001e, + 0x00000062, 0x00000061, 0x00040020, 0x00000063, 0x0000000c, 0x00000062, 0x0004003b, 0x00000063, 0x00000064, 0x0000000c, + 0x0004002b, 0x00000002, 0x0000006b, 0x00000006, 0x0003001d, 0x00000072, 0x00000002, 0x0005001e, 0x00000073, 0x00000002, + 0x00000002, 0x00000072, 0x00040020, 0x00000074, 0x0000000c, 0x00000073, 0x0004003b, 0x00000074, 0x00000075, 0x0000000c, + 0x0004002b, 0x00000002, 0x00000077, 0x00000010, 0x0004002b, 0x00000002, 0x00000088, 0x0dead001, 0x0004002b, 0x00000002, + 0x0000008b, 0x00000002, 0x0004002b, 0x00000002, 0x00000097, 0x00000005, 0x0004002b, 0x00000002, 0x000000a0, 0x00000009, + 0x0004002b, 0x00000002, 0x000000a2, 0x00000008, 0x0004002b, 0x00000002, 0x000000a5, 0x0000000a, 0x0004002b, 0x00000002, + 0x000000aa, 0x00000007, 0x0003001d, 0x000000ac, 0x00000002, 0x0003001e, 0x000000ad, 0x000000ac, 0x00040020, 0x000000ae, + 0x0000000c, 0x000000ad, 0x0004003b, 0x000000ae, 0x000000af, 0x0000000c, 0x0004002b, 0x00000002, 0x000000b9, 0x0000000b, + 0x0004002b, 0x00000002, 0x000000bd, 0x0000000c, 0x0004002b, 0x00000002, 0x000000c1, 0x0000000d, 0x0004002b, 0x00000002, + 0x000000c5, 0x0000000e, 0x0004002b, 0x00000002, 0x000000ca, 0x0000000f, 0x00030029, 0x00000004, 0x000000cf, 0x00050036, + 0x00000004, 0x0000000d, 0x00000000, 0x00000005, 0x00030037, 0x00000002, 0x00000006, 0x00030037, 0x00000003, 0x00000007, + 0x00030037, 0x00000002, 0x00000008, 0x00030037, 0x00000002, 0x00000009, 0x00030037, 0x00000002, 0x0000000a, 0x00030037, + 0x00000002, 0x0000000b, 0x00030037, 0x00000002, 0x0000000c, 0x000200f8, 0x0000000e, 0x0004003b, 0x0000000f, 0x00000010, + 0x00000007, 0x0004003b, 0x0000000f, 0x00000012, 0x00000007, 0x0004003b, 0x0000000f, 0x00000013, 0x00000007, 0x0004003b, + 0x00000035, 0x00000036, 0x00000007, 0x0003003e, 0x00000010, 0x00000011, 0x0003003e, 0x00000012, 0x00000011, 0x0003003e, + 0x00000013, 0x00000011, 0x000200f9, 0x00000014, 0x000200f8, 0x00000014, 0x000400f6, 0x00000016, 0x00000017, 0x00000000, + 0x000200f9, 0x00000015, 0x000200f8, 0x00000015, 0x000500ac, 0x00000004, 0x00000018, 0x0000000b, 0x00000008, 0x000300f7, + 0x0000001a, 0x00000000, 0x000400fa, 0x00000018, 0x00000019, 0x0000001a, 0x000200f8, 0x00000019, 0x0003003e, 0x00000010, + 0x0000001b, 0x0003003e, 0x00000012, 0x00000008, 0x000200f9, 0x00000016, 0x000200f8, 0x0000001a, 0x00070041, 0x00000032, + 0x00000033, 0x0000002e, 0x00000030, 0x00000009, 0x00000031, 0x0004003d, 0x0000001d, 0x00000034, 0x00000033, 0x00060041, + 0x00000039, 0x0000003a, 0x00000034, 0x00000038, 0x0000000a, 0x0006003d, 0x0000001e, 0x0000003b, 0x0000003a, 0x00000002, + 0x00000008, 0x0003003e, 0x00000036, 0x0000003b, 0x00070041, 0x0000003e, 0x0000003f, 0x0000002e, 0x00000030, 0x00000009, + 0x00000030, 0x0004003d, 0x00000024, 0x00000040, 0x0000003f, 0x00050041, 0x0000000f, 0x00000043, 0x00000036, 0x00000042, + 0x0004003d, 0x00000002, 0x00000044, 0x00000043, 0x00050080, 0x00000002, 0x00000045, 0x00000044, 0x0000000b, 0x00070041, + 0x00000049, 0x0000004a, 0x00000040, 0x00000031, 0x00000045, 0x00000042, 0x0006003d, 0x00000002, 0x0000004b, 0x0000004a, + 0x00000002, 0x00000004, 0x000500ae, 0x00000004, 0x0000004d, 0x0000000c, 0x0000004b, 0x000300f7, 0x0000004f, 0x00000000, + 0x000400fa, 0x0000004d, 0x0000004e, 0x0000004f, 0x000200f8, 0x0000004e, 0x0003003e, 0x00000010, 0x00000050, 0x0003003e, + 0x00000012, 0x0000000c, 0x0003003e, 0x00000013, 0x0000004b, 0x000200f9, 0x00000016, 0x000200f8, 0x0000004f, 0x000200f9, + 0x00000017, 0x000200f8, 0x00000017, 0x000400fa, 0x00000053, 0x00000014, 0x00000016, 0x000200f8, 0x00000016, 0x0004003d, + 0x00000002, 0x00000054, 0x00000010, 0x000500ab, 0x00000004, 0x00000055, 0x00000011, 0x00000054, 0x000300f7, 0x00000057, + 0x00000000, 0x000400fa, 0x00000055, 0x00000056, 0x00000057, 0x000200f8, 0x00000056, 0x00060041, 0x0000005d, 0x0000005e, + 0x0000005c, 0x00000031, 0x00000031, 0x0004003d, 0x00000002, 0x0000005f, 0x0000005e, 0x00060041, 0x0000005d, 0x00000066, + 0x00000064, 0x00000031, 0x0000005f, 0x000700ea, 0x00000002, 0x00000067, 0x00000066, 0x00000042, 0x00000011, 0x00000042, + 0x000500ae, 0x00000004, 0x0000006c, 0x00000067, 0x0000006b, 0x000300f7, 0x0000006f, 0x00000000, 0x000400fa, 0x0000006c, + 0x0000006e, 0x0000006f, 0x000200f8, 0x0000006e, 0x000200fe, 0x00000053, 0x000200f8, 0x0000006f, 0x00050041, 0x0000005d, + 0x00000076, 0x00000075, 0x00000030, 0x000700ea, 0x00000002, 0x00000078, 0x00000076, 0x00000042, 0x00000011, 0x00000077, + 0x00050080, 0x00000002, 0x0000007b, 0x00000078, 0x00000077, 0x00050044, 0x00000002, 0x0000007c, 0x00000075, 0x00000002, + 0x0004007c, 0x0000002f, 0x0000007d, 0x0000007c, 0x0004007c, 0x00000002, 0x0000007e, 0x0000007d, 0x000500b2, 0x00000004, + 0x0000007f, 0x0000007b, 0x0000007e, 0x000300f7, 0x00000082, 0x00000000, 0x000400fa, 0x0000007f, 0x00000081, 0x00000082, + 0x000200f8, 0x00000081, 0x00060041, 0x0000005d, 0x00000085, 0x00000075, 0x00000038, 0x00000078, 0x0003003e, 0x00000085, + 0x00000077, 0x00050080, 0x00000002, 0x00000087, 0x00000078, 0x00000042, 0x00060041, 0x0000005d, 0x00000089, 0x00000075, + 0x00000038, 0x00000087, 0x0003003e, 0x00000089, 0x00000088, 0x00050080, 0x00000002, 0x0000008c, 0x00000078, 0x0000008b, + 0x00060041, 0x0000005d, 0x0000008d, 0x00000075, 0x00000038, 0x0000008c, 0x0003003e, 0x0000008d, 0x00000006, 0x00050080, + 0x00000002, 0x0000008f, 0x00000078, 0x0000001b, 0x00050051, 0x00000002, 0x00000090, 0x00000007, 0x00000000, 0x00060041, + 0x0000005d, 0x00000091, 0x00000075, 0x00000038, 0x0000008f, 0x0003003e, 0x00000091, 0x00000090, 0x00050080, 0x00000002, + 0x00000093, 0x00000078, 0x00000050, 0x00050051, 0x00000002, 0x00000094, 0x00000007, 0x00000001, 0x00060041, 0x0000005d, + 0x00000095, 0x00000075, 0x00000038, 0x00000093, 0x0003003e, 0x00000095, 0x00000094, 0x00050080, 0x00000002, 0x00000098, + 0x00000078, 0x00000097, 0x00050051, 0x00000002, 0x00000099, 0x00000007, 0x00000002, 0x00060041, 0x0000005d, 0x0000009a, + 0x00000075, 0x00000038, 0x00000098, 0x0003003e, 0x0000009a, 0x00000099, 0x00050080, 0x00000002, 0x0000009c, 0x00000078, + 0x0000006b, 0x00050051, 0x00000002, 0x0000009d, 0x00000007, 0x00000003, 0x00060041, 0x0000005d, 0x0000009e, 0x00000075, + 0x00000038, 0x0000009c, 0x0003003e, 0x0000009e, 0x0000009d, 0x00050080, 0x00000002, 0x000000a1, 0x00000078, 0x000000a0, + 0x00060041, 0x0000005d, 0x000000a3, 0x00000075, 0x00000038, 0x000000a1, 0x0003003e, 0x000000a3, 0x000000a2, 0x00050080, + 0x00000002, 0x000000a6, 0x00000078, 0x000000a5, 0x0004003d, 0x00000002, 0x000000a7, 0x00000010, 0x00060041, 0x0000005d, + 0x000000a8, 0x00000075, 0x00000038, 0x000000a6, 0x0003003e, 0x000000a8, 0x000000a7, 0x00050080, 0x00000002, 0x000000ab, + 0x00000078, 0x000000aa, 0x00060041, 0x0000005d, 0x000000b0, 0x000000af, 0x00000031, 0x00000031, 0x0004003d, 0x00000002, + 0x000000b1, 0x000000b0, 0x00060041, 0x0000005d, 0x000000b2, 0x00000075, 0x00000038, 0x000000ab, 0x0003003e, 0x000000b2, + 0x000000b1, 0x00050080, 0x00000002, 0x000000b4, 0x00000078, 0x000000a2, 0x00060041, 0x0000005d, 0x000000b5, 0x0000005c, + 0x00000031, 0x00000031, 0x0004003d, 0x00000002, 0x000000b6, 0x000000b5, 0x00060041, 0x0000005d, 0x000000b7, 0x00000075, + 0x00000038, 0x000000b4, 0x0003003e, 0x000000b7, 0x000000b6, 0x00050080, 0x00000002, 0x000000ba, 0x00000078, 0x000000b9, + 0x00060041, 0x0000005d, 0x000000bb, 0x00000075, 0x00000038, 0x000000ba, 0x0003003e, 0x000000bb, 0x00000009, 0x00050080, + 0x00000002, 0x000000be, 0x00000078, 0x000000bd, 0x00060041, 0x0000005d, 0x000000bf, 0x00000075, 0x00000038, 0x000000be, + 0x0003003e, 0x000000bf, 0x0000000a, 0x00050080, 0x00000002, 0x000000c2, 0x00000078, 0x000000c1, 0x00060041, 0x0000005d, + 0x000000c3, 0x00000075, 0x00000038, 0x000000c2, 0x0003003e, 0x000000c3, 0x0000000b, 0x00050080, 0x00000002, 0x000000c6, + 0x00000078, 0x000000c5, 0x0004003d, 0x00000002, 0x000000c7, 0x00000012, 0x00060041, 0x0000005d, 0x000000c8, 0x00000075, + 0x00000038, 0x000000c6, 0x0003003e, 0x000000c8, 0x000000c7, 0x00050080, 0x00000002, 0x000000cb, 0x00000078, 0x000000ca, + 0x0004003d, 0x00000002, 0x000000cc, 0x00000013, 0x00060041, 0x0000005d, 0x000000cd, 0x00000075, 0x00000038, 0x000000cb, + 0x0003003e, 0x000000cd, 0x000000cc, 0x000200f9, 0x00000082, 0x000200f8, 0x00000082, 0x000200fe, 0x00000053, 0x000200f8, + 0x00000057, 0x000200fe, 0x000000cf, 0x00010038, +}; diff --git a/layers/vulkan/generated/instrumentation_non_bindless_oob_texel_buffer_comp.h b/layers/vulkan/generated/instrumentation_non_bindless_oob_texel_buffer_comp.h new file mode 100644 index 00000000000..dfcf333f0df --- /dev/null +++ b/layers/vulkan/generated/instrumentation_non_bindless_oob_texel_buffer_comp.h @@ -0,0 +1,30 @@ +// *** THIS FILE IS GENERATED - DO NOT EDIT *** +// See generate_spirv.py for modifications + +/*************************************************************************** + * + * Copyright (c) 2021-2024 The Khronos Group Inc. + * Copyright (c) 2021-2024 Valve Corporation + * Copyright (c) 2021-2024 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +#pragma once + +#include + +// To view SPIR-V, copy contents of array and paste in https://www.khronos.org/spir/visualizer/ +extern const uint32_t instrumentation_non_bindless_oob_texel_buffer_comp_size; +extern const uint32_t instrumentation_non_bindless_oob_texel_buffer_comp[]; diff --git a/scripts/generate_source.py b/scripts/generate_source.py index d307aa59af6..c9d93fdb683 100755 --- a/scripts/generate_source.py +++ b/scripts/generate_source.py @@ -381,6 +381,8 @@ def main(argv): 'instrumentation_bindless_descriptor_comp.cpp', 'instrumentation_non_bindless_oob_buffer_comp.h', 'instrumentation_non_bindless_oob_buffer_comp.cpp', + 'instrumentation_non_bindless_oob_texel_buffer_comp.h', + 'instrumentation_non_bindless_oob_texel_buffer_comp.cpp', 'instrumentation_ray_query_comp.h', 'instrumentation_ray_query_comp.cpp', 'gpu_av_shader_hash.h' diff --git a/tests/spirv/instrumentation.cpp b/tests/spirv/instrumentation.cpp index 7496672a1a6..3ffe912e72e 100644 --- a/tests/spirv/instrumentation.cpp +++ b/tests/spirv/instrumentation.cpp @@ -25,6 +25,7 @@ static bool print_debug_info = false; static bool all_passes = false; static bool bindless_descriptor_pass = false; static bool non_bindless_oob_buffer_pass = false; +static bool non_bindless_oob_texel_buffer_pass = false; static bool buffer_device_address_pass = false; static bool ray_query_pass = false; static bool debug_printf_pass = false; @@ -44,6 +45,8 @@ USAGE: %s -o Runs BindlessDescriptorPass --non-bindless-oob-buffer Runs NonBindlessOOBBufferPass + --non-bindless-oob-texel-buffer + Runs NonBindlessOOBTexelBufferPass --buffer-device-address Runs BufferDeviceAddressPass --ray-query @@ -83,6 +86,8 @@ bool ParseFlags(int argc, char** argv, const char** out_file) { bindless_descriptor_pass = true; } else if (0 == strcmp(cur_arg, "--non-bindless-oob-buffer")) { non_bindless_oob_buffer_pass = true; + } else if (0 == strcmp(cur_arg, "--non-bindless-oob-texel-buffer")) { + non_bindless_oob_texel_buffer_pass = true; } else if (0 == strcmp(cur_arg, "--buffer-device-address")) { buffer_device_address_pass = true; } else if (0 == strcmp(cur_arg, "--ray-query")) { @@ -154,6 +159,9 @@ int main(int argc, char** argv) { if (all_passes || non_bindless_oob_buffer_pass) { module.RunPassNonBindlessOOBBuffer(); } + if (all_passes || non_bindless_oob_texel_buffer_pass) { + module.RunPassNonBindlessOOBTexelBuffer(); + } if (all_passes || buffer_device_address_pass) { module.RunPassBufferDeviceAddress(); } diff --git a/tests/unit/gpu_av_oob.cpp b/tests/unit/gpu_av_oob.cpp index 4435c980b84..7df5a888315 100644 --- a/tests/unit/gpu_av_oob.cpp +++ b/tests/unit/gpu_av_oob.cpp @@ -1081,6 +1081,63 @@ TEST_F(NegativeGpuAVOOB, TexelFetch) { m_errorMonitor->VerifyFound(); } +TEST_F(NegativeGpuAVOOB, TexelFetchArray) { + TEST_DESCRIPTION("index into texelFetch OOB for an array of TexelBuffers"); + SetTargetApiVersion(VK_API_VERSION_1_2); + AddDisabledFeature(vkt::Feature::robustBufferAccess); + RETURN_IF_SKIP(InitGpuAvFramework()); + RETURN_IF_SKIP(InitState()); + + char const *shader_source = R"glsl( + #version 450 + + layout(set = 0, binding = 0, std430) buffer foo { + vec4 a; + } out_buffer; + + layout(set = 0, binding = 1) uniform samplerBuffer u_buffer[2]; + + void main() { + out_buffer.a = texelFetch(u_buffer[1], 4); + } + )glsl"; + + CreateComputePipelineHelper pipe(*this); + pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, + {1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr}}; + pipe.cs_ = std::make_unique(this, shader_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); + pipe.CreateComputePipeline(); + + VkMemoryPropertyFlags mem_props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + vkt::Buffer out_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, mem_props); + + vkt::Buffer uniform_texel_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, mem_props); + VkBufferViewCreateInfo bvci = vku::InitStructHelper(); + bvci.buffer = uniform_texel_buffer.handle(); + bvci.format = VK_FORMAT_R32_SFLOAT; + bvci.range = VK_WHOLE_SIZE; + vkt::BufferView full_buffer_view(*m_device, bvci); + bvci.range = 16; // only fills 4, but are accessing index[4] + vkt::BufferView partial_buffer_view(*m_device, bvci); + + pipe.descriptor_set_->WriteDescriptorBufferInfo(0, out_buffer.handle(), 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + pipe.descriptor_set_->WriteDescriptorBufferView(1, full_buffer_view.handle(), VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 0); + pipe.descriptor_set_->WriteDescriptorBufferView(1, partial_buffer_view.handle(), VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1); + pipe.descriptor_set_->UpdateDescriptorSets(); + + m_commandBuffer->begin(); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_.handle(), 0, 1, + &pipe.descriptor_set_->set_, 0, nullptr); + vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1); + m_commandBuffer->end(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-uniformBuffers-06935"); + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); + m_errorMonitor->VerifyFound(); +} + TEST_F(NegativeGpuAVOOB, ImageLoad) { TEST_DESCRIPTION("index into a imageLoad OOB"); SetTargetApiVersion(VK_API_VERSION_1_2); @@ -1550,7 +1607,7 @@ TEST_F(NegativeGpuAVOOB, PartialBoundDescriptorCopy) { m_errorMonitor->VerifyFound(); } -TEST_F(NegativeGpuAVOOB, ConstantArrayOOB) { +TEST_F(NegativeGpuAVOOB, ConstantArrayOOBBuffer) { AddDisabledFeature(vkt::Feature::robustBufferAccess); RETURN_IF_SKIP(InitGpuAvFramework()); RETURN_IF_SKIP(InitState()); @@ -1603,3 +1660,66 @@ TEST_F(NegativeGpuAVOOB, ConstantArrayOOB) { m_default_queue->Wait(); m_errorMonitor->VerifyFound(); } + +// This will hang a GPU +// Texel Buffers might not properly under robustBufferAccess like we think, need to investigate +TEST_F(NegativeGpuAVOOB, DISABLED_ConstantArrayOOBTexture) { + TEST_DESCRIPTION("index into texelFetch OOB for an array of TexelBuffers"); + SetTargetApiVersion(VK_API_VERSION_1_2); + AddDisabledFeature(vkt::Feature::robustBufferAccess); + RETURN_IF_SKIP(InitGpuAvFramework()); + RETURN_IF_SKIP(InitState()); + + char const *shader_source = R"glsl( + #version 450 + + layout(set = 0, binding = 0, std430) buffer foo { + int index; + vec4 a; + }; + + layout(set = 0, binding = 1) uniform samplerBuffer u_buffer[2]; + + void main() { + a = texelFetch(u_buffer[index], 0); + } + )glsl"; + + CreateComputePipelineHelper pipe(*this); + pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, + {1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr}}; + pipe.cs_ = std::make_unique(this, shader_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); + pipe.CreateComputePipeline(); + + VkMemoryPropertyFlags mem_props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + vkt::Buffer storage_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, mem_props); + + vkt::Buffer uniform_texel_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, mem_props); + VkBufferViewCreateInfo bvci = vku::InitStructHelper(); + bvci.buffer = uniform_texel_buffer.handle(); + bvci.format = VK_FORMAT_R32_SFLOAT; + bvci.range = VK_WHOLE_SIZE; + vkt::BufferView buffer_view(*m_device, bvci); + + pipe.descriptor_set_->WriteDescriptorBufferInfo(0, storage_buffer.handle(), 0, VK_WHOLE_SIZE, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + pipe.descriptor_set_->WriteDescriptorBufferView(1, buffer_view.handle(), VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 0); + pipe.descriptor_set_->WriteDescriptorBufferView(1, buffer_view.handle(), VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1); + pipe.descriptor_set_->UpdateDescriptorSets(); + + uint32_t *data = (uint32_t *)storage_buffer.memory().map(); + *data = 8; + storage_buffer.memory().unmap(); + + m_commandBuffer->begin(); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_.handle(), 0, 1, + &pipe.descriptor_set_->set_, 0, nullptr); + vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1); + m_commandBuffer->end(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-uniformBuffers-06935"); + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); + m_errorMonitor->VerifyFound(); +} diff --git a/tests/unit/gpu_av_oob_positive.cpp b/tests/unit/gpu_av_oob_positive.cpp index 499118b02c6..b6901fbce62 100644 --- a/tests/unit/gpu_av_oob_positive.cpp +++ b/tests/unit/gpu_av_oob_positive.cpp @@ -579,3 +579,63 @@ TEST_F(PositiveGpuAVOOB, PartialBoundDescriptorCopy) { m_default_queue->Submit(*m_commandBuffer); m_default_queue->Wait(); } + +TEST_F(PositiveGpuAVOOB, TexelFetchArray) { + TEST_DESCRIPTION("index into texelFetch OOB for an array of TexelBuffers"); + SetTargetApiVersion(VK_API_VERSION_1_2); + AddDisabledFeature(vkt::Feature::robustBufferAccess); + RETURN_IF_SKIP(InitGpuAvFramework()); + RETURN_IF_SKIP(InitState()); + + char const *shader_source = R"glsl( + #version 450 + + layout(set = 0, binding = 0, std430) buffer foo { + vec4 a; + vec4 b; + } out_buffer; + + layout(set = 0, binding = 1) uniform samplerBuffer u_buffer[2]; + + void main() { + out_buffer.a = texelFetch(u_buffer[0], 4); // valid + // Will not ever get into this check + if (gl_WorkGroupID.x == 987) { + out_buffer.b = texelFetch(u_buffer[1], 4); // invalid + } + } + )glsl"; + + CreateComputePipelineHelper pipe(*this); + pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, + {1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr}}; + pipe.cs_ = std::make_unique(this, shader_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); + pipe.CreateComputePipeline(); + + VkMemoryPropertyFlags mem_props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + vkt::Buffer out_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, mem_props); + + vkt::Buffer uniform_texel_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, mem_props); + VkBufferViewCreateInfo bvci = vku::InitStructHelper(); + bvci.buffer = uniform_texel_buffer.handle(); + bvci.format = VK_FORMAT_R32_SFLOAT; + bvci.range = VK_WHOLE_SIZE; + vkt::BufferView full_buffer_view(*m_device, bvci); + bvci.range = 16; // only fills 4, but are accessing index[4] + vkt::BufferView partial_buffer_view(*m_device, bvci); + + pipe.descriptor_set_->WriteDescriptorBufferInfo(0, out_buffer.handle(), 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + pipe.descriptor_set_->WriteDescriptorBufferView(1, full_buffer_view.handle(), VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 0); + pipe.descriptor_set_->WriteDescriptorBufferView(1, partial_buffer_view.handle(), VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1); + pipe.descriptor_set_->UpdateDescriptorSets(); + + m_commandBuffer->begin(); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_.handle(), 0, 1, + &pipe.descriptor_set_->set_, 0, nullptr); + vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1); + m_commandBuffer->end(); + + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); +}