Repository: KhronosGroup/Vulkan-ValidationLayers
Pull request #9653: gpuav: Remove more pass member variables
Author: login: spencer-lunarg
Created: 2025-03-12T19:54:46Z | Merged: 2025-03-13T15:01:35Z

Most passes have a common trend

1. Call `RequiresInstrumentation` and build up values
2. Call `CreateFunctionCall` and use those values

Currently we just stored everything as a global member variable which made it hard to grasp the lifetime

This removes all the "instruction only" lifetime variables to a struct that gets passed around as a reference to explain where the life time starts/ends

Chose `Meta` because it is unique, accurate , and doesn't add yet-another `instruction` name to the name space


Diff:
diff --git a/BUILD.gn b/BUILD.gn
index ebd61e299f4..70d567beb64 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -218,8 +218,6 @@ vvl_sources = [
   "layers/gpuav/spirv/module.h",
   "layers/gpuav/spirv/inject_conditional_function_pass.cpp",
   "layers/gpuav/spirv/inject_conditional_function_pass.h",
-  "layers/gpuav/spirv/inject_function_pass.cpp",
-  "layers/gpuav/spirv/inject_function_pass.h",
   "layers/gpuav/spirv/pass.cpp",
   "layers/gpuav/spirv/pass.h",
   "layers/gpuav/spirv/ray_query_pass.cpp",
diff --git a/layers/gpuav/spirv/CMakeLists.txt b/layers/gpuav/spirv/CMakeLists.txt
index 99caf7ed701..b7577301dc8 100644
--- a/layers/gpuav/spirv/CMakeLists.txt
+++ b/layers/gpuav/spirv/CMakeLists.txt
@@ -45,8 +45,6 @@ target_sources(gpu_av_spirv PRIVATE
     type_manager.cpp
     inject_conditional_function_pass.h
     inject_conditional_function_pass.cpp
-    inject_function_pass.h
-    inject_function_pass.cpp
     pass.h
     pass.cpp
     ${VVL_SOURCE_DIR}/layers/${API_TYPE}/generated/spirv_grammar_helper.cpp
diff --git a/layers/gpuav/spirv/buffer_device_address_pass.cpp b/layers/gpuav/spirv/buffer_device_address_pass.cpp
index 99d844e5463..c7acc0fb519 100644
--- a/layers/gpuav/spirv/buffer_device_address_pass.cpp
+++ b/layers/gpuav/spirv/buffer_device_address_pass.cpp
@@ -37,19 +37,19 @@ uint32_t BufferDeviceAddressPass::GetLinkFunctionId() {
     return link_function_id;
 }
 
-uint32_t BufferDeviceAddressPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it,
-                                                     const InjectionData& injection_data) {
+uint32_t BufferDeviceAddressPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data,
+                                                     const InstructionMeta& meta) {
     // Convert reference pointer to uint64
-    const uint32_t pointer_id = target_instruction_->Operand(0);
+    const uint32_t pointer_id = meta.target_instruction->Operand(0);
     const Type& uint64_type = module_.type_manager_.GetTypeInt(64, 0);
     const uint32_t convert_id = module_.TakeNextId();
     block.CreateInstruction(spv::OpConvertPtrToU, {uint64_type.Id(), convert_id, pointer_id}, inst_it);
 
-    const Constant& length_constant = module_.type_manager_.GetConstantUInt32(type_length_);
-    const uint32_t opcode = target_instruction_->Opcode();
+    const Constant& length_constant = module_.type_manager_.GetConstantUInt32(meta.type_length);
+    const uint32_t opcode = meta.target_instruction->Opcode();
     const Constant& access_opcode = module_.type_manager_.GetConstantUInt32(opcode);
 
-    const Constant& alignment_constant = module_.type_manager_.GetConstantUInt32(alignment_literal_);
+    const Constant& alignment_constant = module_.type_manager_.GetConstantUInt32(meta.alignment_literal);
 
     const uint32_t function_result = module_.TakeNextId();
     const uint32_t function_def = GetLinkFunctionId();
@@ -64,13 +64,7 @@ uint32_t BufferDeviceAddressPass::CreateFunctionCall(BasicBlock& block, Instruct
     return function_result;
 }
 
-void BufferDeviceAddressPass::Reset() {
-    target_instruction_ = nullptr;
-    alignment_literal_ = 0;
-    type_length_ = 0;
-}
-
-bool BufferDeviceAddressPass::RequiresInstrumentation(const Function& function, const Instruction& inst) {
+bool BufferDeviceAddressPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) {
     const uint32_t opcode = inst.Opcode();
     if (opcode == spv::OpLoad || opcode == spv::OpStore) {
         // We only care if there is an Aligned Memory Operands
@@ -86,14 +80,14 @@ bool BufferDeviceAddressPass::RequiresInstrumentation(const Function& function,
         }
         // Even if they are other Memory Operands the spec says it is ordered by smallest bit first,
         // Luckily |Aligned| is the smallest bit that can have an operand so we know it is here
-        alignment_literal_ = inst.Word(alignment_word_index);
+        meta.alignment_literal = inst.Word(alignment_word_index);
 
         // Aligned 0 was not being validated (https://github.com/KhronosGroup/glslang/issues/3893)
         // This is nonsense and we should skip (as it should be validated in spirv-val)
-        if (!IsPowerOfTwo(alignment_literal_)) return false;
+        if (!IsPowerOfTwo(meta.alignment_literal)) return false;
     } else if (AtomicOperation(opcode)) {
         // Atomics are naturally aligned and by setting this to 1, it will always pass the alignment check
-        alignment_literal_ = 1;
+        meta.alignment_literal = 1;
     } else {
         return false;
     }
@@ -132,8 +126,8 @@ bool BufferDeviceAddressPass::RequiresInstrumentation(const Function& function,
     }
 
     // Save information to be used to make the Function
-    target_instruction_ = &inst;
-    type_length_ = module_.type_manager_.TypeLength(*accessed_type);
+    meta.target_instruction = &inst;
+    meta.type_length = module_.type_manager_.TypeLength(*accessed_type);
     return true;
 }
 
diff --git a/layers/gpuav/spirv/buffer_device_address_pass.h b/layers/gpuav/spirv/buffer_device_address_pass.h
index 287aeace770..aa94301cd1d 100644
--- a/layers/gpuav/spirv/buffer_device_address_pass.h
+++ b/layers/gpuav/spirv/buffer_device_address_pass.h
@@ -30,15 +30,12 @@ class BufferDeviceAddressPass : public InjectConditionalFunctionPass {
     void PrintDebugInfo() const final;
 
   private:
-    bool RequiresInstrumentation(const Function& function, const Instruction& inst) final;
-    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data) final;
-    void Reset() final;
+    bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) final;
+    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data,
+                                const InstructionMeta& meta) final;
 
     uint32_t link_function_id = 0;
     uint32_t GetLinkFunctionId();
-
-    uint32_t alignment_literal_ = 0;
-    uint32_t type_length_ = 0;
 };
 
 }  // namespace spirv
diff --git a/layers/gpuav/spirv/debug_printf_pass.cpp b/layers/gpuav/spirv/debug_printf_pass.cpp
index 06587f0fb94..2d895c15f04 100644
--- a/layers/gpuav/spirv/debug_printf_pass.cpp
+++ b/layers/gpuav/spirv/debug_printf_pass.cpp
@@ -42,9 +42,9 @@ uint32_t DebugPrintfPass::GetLinkFunctionId(uint32_t argument_count) {
     return link_function_id;
 }
 
-bool DebugPrintfPass::RequiresInstrumentation(const Instruction& inst) {
+bool DebugPrintfPass::RequiresInstrumentation(const Instruction& inst, InstructionMeta& meta) {
     if (inst.Opcode() == spv::OpExtInst && inst.Word(3) == ext_import_id_ && inst.Word(4) == NonSemanticDebugPrintfDebugPrintf) {
-        target_instruction_ = &inst;
+        meta.target_instruction = &inst;
         return true;
     }
     return false;
@@ -52,7 +52,7 @@ bool DebugPrintfPass::RequiresInstrumentation(const Instruction& inst) {
 
 // Takes the various arguments and casts them to a valid uint32_t to be passed as a parameter in the function
 void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& argument_type, std::vector<uint32_t>& params,
-                                           BasicBlock& block, InstructionIt* inst_it) {
+                                           BasicBlock& block, InstructionIt* inst_it, ParamMeta& p_meta) {
     const Type& uint32_type = module_.type_manager_.GetTypeInt(32, false);
     const uint32_t uint32_type_id = uint32_type.Id();
 
@@ -65,7 +65,7 @@ void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& arg
             for (uint32_t i = 0; i < component_count; i++) {
                 const uint32_t extract_id = module_.TakeNextId();
                 block.CreateInstruction(spv::OpCompositeExtract, {component_type_id, extract_id, argument_id, i}, inst_it);
-                CreateFunctionParams(extract_id, *component_type, params, block, inst_it);
+                CreateFunctionParams(extract_id, *component_type, params, block, inst_it, p_meta);
             }
             break;
         }
@@ -83,20 +83,20 @@ void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& arg
                 incoming_id = bitcast_id;
 
                 if (width == 8) {
-                    if (expanded_parameter_count_ > 31) {
+                    if (p_meta.expanded_parameter_count > 31) {
                         module_.InternalWarning("DEBUG-PRINTF-SIGNED-8-MASK",
                                                 "More than 32 expanded parameters, can't properly detect 8-bit signed ints [Simple "
                                                 "fix is to turn long printf() into 2 shorter printf() calls]");
                     } else {
-                        signed_8_bitmask_ |= 1 << expanded_parameter_count_;
+                        p_meta.signed_8_bitmask |= 1 << p_meta.expanded_parameter_count;
                     }
                 } else if (width == 16) {
-                    if (expanded_parameter_count_ > 31) {
+                    if (p_meta.expanded_parameter_count > 31) {
                         module_.InternalWarning("DEBUG-PRINTF-SIGNED-16-MASK",
                                                 "More than 32 expanded parameters, can't properly detect 16-bit signed ints "
                                                 "[Simple fix is to turn long printf() into 2 shorter printf() calls]");
                     } else {
-                        signed_16_bitmask_ |= 1 << expanded_parameter_count_;
+                        p_meta.signed_16_bitmask |= 1 << p_meta.expanded_parameter_count;
                     }
                 }
             }
@@ -105,15 +105,15 @@ void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& arg
                 const uint32_t uconvert_id = module_.TakeNextId();
                 block.CreateInstruction(spv::OpUConvert, {uint32_type_id, uconvert_id, incoming_id}, inst_it);
                 params.push_back(uconvert_id);
-                expanded_parameter_count_++;
+                p_meta.expanded_parameter_count++;
             } else if (width == 32) {
                 params.push_back(incoming_id);
-                expanded_parameter_count_++;
+                p_meta.expanded_parameter_count++;
             } else if (width == 64) {
                 const uint32_t uconvert_high_id = module_.TakeNextId();
                 block.CreateInstruction(spv::OpUConvert, {uint32_type_id, uconvert_high_id, incoming_id}, inst_it);
                 params.push_back(uconvert_high_id);
-                expanded_parameter_count_++;
+                p_meta.expanded_parameter_count++;
 
                 const uint32_t uint64_type_id = module_.type_manager_.GetTypeInt(64, false).Id();
                 const uint32_t shift_right_id = module_.TakeNextId();
@@ -140,20 +140,20 @@ void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& arg
                 const uint32_t bitcast_id = module_.TakeNextId();
                 block.CreateInstruction(spv::OpBitcast, {uint32_type_id, bitcast_id, fconvert_id}, inst_it);
                 params.push_back(bitcast_id);
-                expanded_parameter_count_++;
+                p_meta.expanded_parameter_count++;
             } else if (width == 32) {
                 const uint32_t bitcast_id = module_.TakeNextId();
                 block.CreateInstruction(spv::OpBitcast, {uint32_type_id, bitcast_id, argument_id}, inst_it);
                 params.push_back(bitcast_id);
-                expanded_parameter_count_++;
+                p_meta.expanded_parameter_count++;
             } else if (width == 64) {
-                if (expanded_parameter_count_ > 31) {
+                if (p_meta.expanded_parameter_count > 31) {
                     // It is very unlikely to hit this
                     module_.InternalWarning("DEBUG-PRINTF-DOUBLE-MASK",
                                             "More than 32 expanded parameters, can't properly detect 64-bit float [Simple fix is "
                                             "to turn long printf() into 2 shorter printf() calls]");
                 } else {
-                    double_bitmask_ |= 1 << expanded_parameter_count_;
+                    p_meta.double_bitmask |= 1 << p_meta.expanded_parameter_count;
                 }
 
                 if (!module_.enabled_features_.shaderInt64) {
@@ -171,7 +171,7 @@ void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& arg
                 const uint32_t uconvert_high_id = module_.TakeNextId();
                 block.CreateInstruction(spv::OpUConvert, {uint32_type_id, uconvert_high_id, bitcast_id}, inst_it);
                 params.push_back(uconvert_high_id);
-                expanded_parameter_count_++;
+                p_meta.expanded_parameter_count++;
 
                 const uint32_t shift_right_id = module_.TakeNextId();
                 const uint32_t constant_32_id = module_.type_manager_.GetConstantUInt32(32).Id();
@@ -194,7 +194,7 @@ void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& arg
             const uint32_t select_id = module_.TakeNextId();
             block.CreateInstruction(spv::OpSelect, {uint32_type_id, select_id, argument_id, one_id, zero_id}, inst_it);
             params.push_back(select_id);
-            expanded_parameter_count_++;
+            p_meta.expanded_parameter_count++;
             break;
         }
 
@@ -207,12 +207,12 @@ void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& arg
             const uint32_t extract_id_0 = module_.TakeNextId();
             block.CreateInstruction(spv::OpCompositeExtract, {uint32_type_id, extract_id_0, bitcast_id, 0}, inst_it);
             params.push_back(extract_id_0);
-            expanded_parameter_count_++;
+            p_meta.expanded_parameter_count++;
 
             const uint32_t extract_id_1 = module_.TakeNextId();
             block.CreateInstruction(spv::OpCompositeExtract, {uint32_type_id, extract_id_1, bitcast_id, 1}, inst_it);
             params.push_back(extract_id_1);
-            expanded_parameter_count_++;
+            p_meta.expanded_parameter_count++;
             break;
         }
 
@@ -222,16 +222,16 @@ void DebugPrintfPass::CreateFunctionParams(uint32_t argument_id, const Type& arg
     }
 }
 
-void DebugPrintfPass::CreateFunctionCall(BasicBlockIt block_it, InstructionIt* inst_it) {
+void DebugPrintfPass::CreateFunctionCall(BasicBlockIt block_it, InstructionIt* inst_it, const InstructionMeta& meta) {
     BasicBlock& block = **block_it;
     Function& block_func = block.function_;
     // need to call to get the underlying 4 IDs (simpler to pass in as 4 uint then a uvec4)
     GetStageInfo(block_func, block_it, *inst_it);
 
-    const uint32_t inst_position = target_instruction_->GetPositionIndex();
+    const uint32_t inst_position = meta.target_instruction->GetPositionIndex();
     auto inst_position_constant = module_.type_manager_.CreateConstantUInt32(inst_position);
 
-    const uint32_t string_id = target_instruction_->Word(5);
+    const uint32_t string_id = meta.target_instruction->Word(5);
     auto string_id_constant = module_.type_manager_.CreateConstantUInt32(string_id);
 
     const uint32_t void_type = module_.type_manager_.GetTypeVoid().Id();
@@ -256,11 +256,12 @@ void DebugPrintfPass::CreateFunctionCall(BasicBlockIt block_it, InstructionIt* i
                                                   block_func.stage_info_z_id_,
                                                   block_func.stage_info_w_id_};
 
+    ParamMeta param_meta;
     // where we find the first arugment in OpExtInst instruction
     const uint32_t first_argument_offset = 6;
-    const uint32_t argument_count = target_instruction_->Length() - first_argument_offset;
+    const uint32_t argument_count = meta.target_instruction->Length() - first_argument_offset;
     for (uint32_t i = 0; i < argument_count; i++) {
-        const uint32_t argument_id = target_instruction_->Word(first_argument_offset + i);
+        const uint32_t argument_id = meta.target_instruction->Word(first_argument_offset + i);
         const Instruction* argument_inst = nullptr;
         const Constant* constant = module_.type_manager_.FindConstantById(argument_id);
         if (constant) {
@@ -273,7 +274,7 @@ void DebugPrintfPass::CreateFunctionCall(BasicBlockIt block_it, InstructionIt* i
         const Type* argument_type = module_.type_manager_.FindTypeById(argument_inst->TypeId());
         assert(argument_type);  // type needs to have been declared already
 
-        CreateFunctionParams(argument_inst->ResultId(), *argument_type, function_call_params, block, inst_it);
+        CreateFunctionParams(argument_inst->ResultId(), *argument_type, function_call_params, block, inst_it, param_meta);
     }
 
     // 3 params are the [result, function type, and function ID]
@@ -283,14 +284,14 @@ void DebugPrintfPass::CreateFunctionCall(BasicBlockIt block_it, InstructionIt* i
 
     // patch in params
     function_call_params[function_def_slot] = function_def;
-    function_call_params[double_bitmask_slot] = module_.type_manager_.GetConstantUInt32(double_bitmask_).Id();
-    function_call_params[signed_8_bitmask_slot] = module_.type_manager_.GetConstantUInt32(signed_8_bitmask_).Id();
-    function_call_params[signed_16_bitmask_slot] = module_.type_manager_.GetConstantUInt32(signed_16_bitmask_).Id();
+    function_call_params[double_bitmask_slot] = module_.type_manager_.GetConstantUInt32(param_meta.double_bitmask).Id();
+    function_call_params[signed_8_bitmask_slot] = module_.type_manager_.GetConstantUInt32(param_meta.signed_8_bitmask).Id();
+    function_call_params[signed_16_bitmask_slot] = module_.type_manager_.GetConstantUInt32(param_meta.signed_16_bitmask).Id();
 
     block.CreateInstruction(spv::OpFunctionCall, function_call_params, inst_it);
 }
 
-void DebugPrintfPass::CreateDescriptorSet() {
+uint32_t DebugPrintfPass::CreateDescriptorSet() {
     // Create descriptor set to match output buffer
     // The following is what the GLSL would look like
     //
@@ -325,18 +326,20 @@ void DebugPrintfPass::CreateDescriptorSet() {
 
     // create a storage buffer interface variable
     const Type& pointer_type = module_.type_manager_.GetTypePointer(spv::StorageClassStorageBuffer, struct_type);
-    output_buffer_variable_id_ = module_.TakeNextId();
+    const uint32_t output_buffer_variable_id = module_.TakeNextId();
     auto new_inst = std::make_unique<Instruction>(4, spv::OpVariable);
-    new_inst->Fill({pointer_type.Id(), output_buffer_variable_id_, spv::StorageClassStorageBuffer});
+    new_inst->Fill({pointer_type.Id(), output_buffer_variable_id, spv::StorageClassStorageBuffer});
     module_.type_manager_.AddVariable(std::move(new_inst), pointer_type);
-    module_.AddInterfaceVariables(output_buffer_variable_id_, spv::StorageClassStorageBuffer);
+    module_.AddInterfaceVariables(output_buffer_variable_id, spv::StorageClassStorageBuffer);
 
-    module_.AddDecoration(output_buffer_variable_id_, spv::DecorationDescriptorSet,
+    module_.AddDecoration(output_buffer_variable_id, spv::DecorationDescriptorSet,
                           {module_.settings_.output_buffer_descriptor_set});
-    module_.AddDecoration(output_buffer_variable_id_, spv::DecorationBinding, {binding_slot_});
+    module_.AddDecoration(output_buffer_variable_id, spv::DecorationBinding, {binding_slot_});
+
+    return output_buffer_variable_id;
 }
 
-void DebugPrintfPass::CreateBufferWriteFunction(uint32_t argument_count, uint32_t function_id) {
+void DebugPrintfPass::CreateBufferWriteFunction(uint32_t argument_count, uint32_t function_id, uint32_t output_buffer_variable_id) {
     // Currently this is generated by the number of arguments
     // The following is what the GLSL would look like
     //
@@ -404,7 +407,7 @@ void DebugPrintfPass::CreateBufferWriteFunction(uint32_t argument_count, uint32_
     // Atomically get a write index in the output buffer, and check if this index is with buffer's bounds
     {
         const uint32_t access_chain_id = module_.TakeNextId();
-        check_block->CreateInstruction(spv::OpAccessChain, {pointer_type_id, access_chain_id, output_buffer_variable_id_, zero_id});
+        check_block->CreateInstruction(spv::OpAccessChain, {pointer_type_id, access_chain_id, output_buffer_variable_id, zero_id});
 
         atomic_add_id = module_.TakeNextId();
         const uint32_t scope_invok_id = module_.type_manager_.GetConstantUInt32(spv::ScopeInvocation).Id();
@@ -416,7 +419,7 @@ void DebugPrintfPass::CreateBufferWriteFunction(uint32_t argument_count, uint32_
         check_block->CreateInstruction(spv::OpIAdd, {uint32_type_id, int_add_id, atomic_add_id, byte_written_id});
 
         const uint32_t array_length_id = module_.TakeNextId();
-        check_block->CreateInstruction(spv::OpArrayLength, {uint32_type_id, array_length_id, output_buffer_variable_id_, 1});
+        check_block->CreateInstruction(spv::OpArrayLength, {uint32_type_id, array_length_id, output_buffer_variable_id, 1});
 
         const uint32_t less_than_equal_id = module_.TakeNextId();
         const uint32_t bool_type_id = module_.type_manager_.GetTypeBool().Id();
@@ -436,7 +439,7 @@ void DebugPrintfPass::CreateBufferWriteFunction(uint32_t argument_count, uint32_
 
         const uint32_t access_chain_id = module_.TakeNextId();
         store_block->CreateInstruction(spv::OpAccessChain,
-                                       {pointer_type_id, access_chain_id, output_buffer_variable_id_, one_id, int_add_id});
+                                       {pointer_type_id, access_chain_id, output_buffer_variable_id, one_id, int_add_id});
 
         store_block->CreateInstruction(spv::OpStore, {access_chain_id, byte_written_id});
     }
@@ -448,7 +451,7 @@ void DebugPrintfPass::CreateBufferWriteFunction(uint32_t argument_count, uint32_
 
         const uint32_t access_chain_id = module_.TakeNextId();
         store_block->CreateInstruction(spv::OpAccessChain,
-                                       {pointer_type_id, access_chain_id, output_buffer_variable_id_, one_id, int_add_id});
+                                       {pointer_type_id, access_chain_id, output_buffer_variable_id, one_id, int_add_id});
 
         const uint32_t shader_id = module_.type_manager_.GetConstantUInt32(module_.settings_.shader_id).Id();
         store_block->CreateInstruction(spv::OpStore, {access_chain_id, shader_id});
@@ -463,7 +466,7 @@ void DebugPrintfPass::CreateBufferWriteFunction(uint32_t argument_count, uint32_
 
         const uint32_t access_chain_id = module_.TakeNextId();
         store_block->CreateInstruction(spv::OpAccessChain,
-                                       {pointer_type_id, access_chain_id, output_buffer_variable_id_, one_id, int_add_id});
+                                       {pointer_type_id, access_chain_id, output_buffer_variable_id, one_id, int_add_id});
 
         store_block->CreateInstruction(spv::OpStore, {access_chain_id, function_param_ids[i]});
     }
@@ -480,15 +483,6 @@ void DebugPrintfPass::CreateBufferWriteFunction(uint32_t argument_count, uint32_
     }
 }
 
-// Used between injections of a function
-void DebugPrintfPass::Reset() {
-    target_instruction_ = nullptr;
-    double_bitmask_ = 0;
-    signed_8_bitmask_ = 0;
-    signed_16_bitmask_ = 0;
-    expanded_parameter_count_ = 0;
-}
-
 bool DebugPrintfPass::Instrument() {
     for (const auto& inst : module_.ext_inst_imports_) {
         const char* import_string = inst->GetAsString(2);
@@ -506,8 +500,9 @@ bool DebugPrintfPass::Instrument() {
         for (auto block_it = function->blocks_.begin(); block_it != function->blocks_.end(); ++block_it) {
             auto& block_instructions = (*block_it)->instructions_;
             for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) {
-                if (!RequiresInstrumentation(*(inst_it->get()))) continue;
-                if (!Validate(*(function.get()))) continue;  // if not valid, don't attempt to instrument it
+                InstructionMeta meta;
+                if (!RequiresInstrumentation(*(inst_it->get()), meta)) continue;
+                if (!Validate(*(function.get()), meta)) continue;  // if not valid, don't attempt to instrument it
                 instrumentations_count_++;
 
                 // Save the OpString here so we can use it later
@@ -521,15 +516,13 @@ bool DebugPrintfPass::Instrument() {
                     }
                 }
 
-                CreateFunctionCall(block_it, &inst_it);
+                CreateFunctionCall(block_it, &inst_it, meta);
 
                 // remove the OpExtInst incase they don't support VK_KHR_non_semantic_info
                 if (!module_.settings_.support_non_semantic_info) {
                     inst_it = block_instructions.erase(inst_it);
                     inst_it--;
                 }
-
-                Reset();
             }
         }
     }
@@ -537,11 +530,11 @@ bool DebugPrintfPass::Instrument() {
         return false;
     }
 
-    CreateDescriptorSet();
+    const uint32_t output_buffer_variable_id = CreateDescriptorSet();
 
     // Here we "link" the functions, but since it is all generated, no need to go through the LinkInfo flow
     for (const auto& [number_of_args, function_id] : function_id_map_) {
-        CreateBufferWriteFunction(number_of_args, function_id);
+        CreateBufferWriteFunction(number_of_args, function_id, output_buffer_variable_id);
     }
 
     // remove the everything else possible incase they don't support VK_KHR_non_semantic_info
@@ -580,7 +573,7 @@ void DebugPrintfPass::PrintDebugInfo() const {
 // a different HLL and Tool consuming it.
 // Currently RenderDoc and the Validation Layers both follow the same syntax, but that also could possibly change.
 // Therefore, we validate these here based on the VVL implementation only
-bool DebugPrintfPass::Validate(const Function& current_function) {
+bool DebugPrintfPass::Validate(const Function& current_function, const InstructionMeta& meta) {
     static const char* tag = "DEBUG-PRINTF-FORMATTING";
 
     struct ParamInfo {
@@ -594,12 +587,12 @@ bool DebugPrintfPass::Validate(const Function& current_function) {
     // where we find the first arugment in OpExtInst instruction
     const uint32_t first_argument_offset = 6;
 
-    if (target_instruction_->Length() < first_argument_offset) {
+    if (meta.target_instruction->Length() < first_argument_offset) {
         module_.InternalError(tag, "OpExtInst in a invalid SPIR-V format and should have been caught in spirv-val");
         return false;
     }
 
-    uint32_t string_id = target_instruction_->Word(5);
+    uint32_t string_id = meta.target_instruction->Word(5);
     const char* op_string = nullptr;
     for (const auto& inst : module_.debug_source_) {
         if (inst->Opcode() == spv::OpString && inst->ResultId() == string_id) {
@@ -761,7 +754,7 @@ bool DebugPrintfPass::Validate(const Function& current_function) {
     }
     if (!valid) return false;
 
-    const uint32_t argument_count = target_instruction_->Length() - first_argument_offset;
+    const uint32_t argument_count = meta.target_instruction->Length() - first_argument_offset;
     if (argument_count > param_infos.size()) {
         std::string err_msg = "OpString \"" + print_op_string() + "\" contains only " + std::to_string(param_infos.size()) +
                               " modifiers, but " + std::to_string(argument_count) +
@@ -779,7 +772,7 @@ bool DebugPrintfPass::Validate(const Function& current_function) {
     const uint32_t count = std::min(argument_count, (uint32_t)param_infos.size());
     for (uint32_t i = 0; i < count; i++) {
         const ParamInfo& param = param_infos[i];
-        const uint32_t argument_id = target_instruction_->Word(first_argument_offset + i);
+        const uint32_t argument_id = meta.target_instruction->Word(first_argument_offset + i);
 
         const Type* argument_type = nullptr;
         if (const Constant* constant = module_.type_manager_.FindConstantById(argument_id)) {
diff --git a/layers/gpuav/spirv/debug_printf_pass.h b/layers/gpuav/spirv/debug_printf_pass.h
index 398f5b22e8f..2e6c47748a7 100644
--- a/layers/gpuav/spirv/debug_printf_pass.h
+++ b/layers/gpuav/spirv/debug_printf_pass.h
@@ -34,15 +34,31 @@ class DebugPrintfPass : public Pass {
     void PrintDebugInfo() const final;
 
   private:
-    bool RequiresInstrumentation(const Instruction& inst);
-    void CreateFunctionCall(BasicBlockIt block_it, InstructionIt* inst_it);
+    // This is metadata tied to a single instruction gathered during RequiresInstrumentation() to be used later
+    struct InstructionMeta {
+        const Instruction* target_instruction = nullptr;
+    };
+
+    // Once we want to create a function, we need to gather temporary data while building the parameters
+    struct ParamMeta {
+        // Used to detect where 64-bit floats are
+        uint32_t double_bitmask = 0;
+        // Used to detect where signed ints are 8 or 16 bits
+        uint32_t signed_8_bitmask = 0;
+        uint32_t signed_16_bitmask = 0;
+        // Count number of parameters the CPU will need to print out
+        // This expands vectors and accounts for 64-bit parameters
+        uint32_t expanded_parameter_count = 0;
+    };
+
+    bool RequiresInstrumentation(const Instruction& inst, InstructionMeta& meta);
+    void CreateFunctionCall(BasicBlockIt block_it, InstructionIt* inst_it, const InstructionMeta& meta);
     void CreateFunctionParams(uint32_t argument_id, const Type& argument_type, std::vector<uint32_t>& params, BasicBlock& block,
-                              InstructionIt* inst_it);
-    void CreateDescriptorSet();
-    void CreateBufferWriteFunction(uint32_t argument_count, uint32_t function_id);
-    void Reset() final;
+                              InstructionIt* inst_it, ParamMeta& p_meta);
+    uint32_t CreateDescriptorSet();
+    void CreateBufferWriteFunction(uint32_t argument_count, uint32_t function_id, uint32_t output_buffer_variable_id);
 
-    bool Validate(const Function& current_function);
+    bool Validate(const Function& current_function, const InstructionMeta& meta);
 
     // for debugging instrumented shaders
     std::vector<InternalOnlyDebugPrintf>& intenral_only_debug_printf_;
@@ -53,17 +69,6 @@ class DebugPrintfPass : public Pass {
     // <number of arguments in the function call, function id>
     vvl::unordered_map<uint32_t, uint32_t> function_id_map_;
     uint32_t GetLinkFunctionId(uint32_t argument_count);
-
-    uint32_t output_buffer_variable_id_ = 0;
-
-    // Used to detect where 64-bit floats are
-    uint32_t double_bitmask_ = 0;
-    // Used to detect where signed ints are 8 or 16 bits
-    uint32_t signed_8_bitmask_ = 0;
-    uint32_t signed_16_bitmask_ = 0;
-    // Count number of parameters the CPU will need to print out
-    // This expands vectors and accounts for 64-bit parameters
-    uint32_t expanded_parameter_count_ = 0;
 };
 
 }  // namespace spirv
diff --git a/layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp b/layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
index a15ece3de1f..e4552c11689 100644
--- a/layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
+++ b/layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
@@ -110,7 +110,7 @@ uint32_t DescriptorClassGeneralBufferPass::FindLastByteOffset(uint32_t descripto
             } break;
             case SpvType::kMatrix: {
                 if (matrix_stride == 0) {
-                    module_.InternalError(Name(), "GetOffset is missing matrix stride");
+                    module_.InternalError(Name(), "FindLastByteOffset is missing matrix stride");
                 }
                 in_matrix = true;
                 uint32_t vec_type_id = current_type->inst_.Operand(0);
@@ -162,7 +162,7 @@ uint32_t DescriptorClassGeneralBufferPass::FindLastByteOffset(uint32_t descripto
                 current_type_id = current_type->inst_.Operand(constant_value);  // Get element type for next step
             } break;
             default: {
-                module_.InternalError(Name(), "GetLastByte has unexpected non-composite type");
+                module_.InternalError(Name(), "FindLastByteOffset has unexpected non-composite type");
             } break;
         }
 
@@ -184,15 +184,16 @@ uint32_t DescriptorClassGeneralBufferPass::FindLastByteOffset(uint32_t descripto
 }
 
 uint32_t DescriptorClassGeneralBufferPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it,
-                                                              const InjectionData& injection_data) {
-    assert(!access_chain_insts_.empty());
-    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 InjectionData& injection_data, const InstructionMeta& meta) {
+    assert(!meta.access_chain_insts.empty());
+    const Constant& set_constant = module_.type_manager_.GetConstantUInt32(meta.descriptor_set);
+    const Constant& binding_constant = module_.type_manager_.GetConstantUInt32(meta.descriptor_binding);
+    const uint32_t descriptor_index_id = CastToUint32(meta.descriptor_index_id, block, inst_it);  // might be int32
 
-    descriptor_offset_id_ = GetLastByte(*descriptor_type_, access_chain_insts_, block, inst_it);  // Get Last Byte Index
+    const uint32_t descriptor_offset_id =
+        GetLastByte(*meta.descriptor_type, meta.access_chain_insts, block, inst_it);  // Get Last Byte Index
 
-    BindingLayout binding_layout = module_.set_index_to_bindings_layout_lut_[descriptor_set_][descriptor_binding_];
+    BindingLayout binding_layout = module_.set_index_to_bindings_layout_lut_[meta.descriptor_set][meta.descriptor_binding];
     const Constant& binding_layout_offset = module_.type_manager_.GetConstantUInt32(binding_layout.start);
 
     const uint32_t function_result = module_.TakeNextId();
@@ -202,22 +203,14 @@ uint32_t DescriptorClassGeneralBufferPass::CreateFunctionCall(BasicBlock& block,
     block.CreateInstruction(
         spv::OpFunctionCall,
         {bool_type, function_result, function_def, injection_data.inst_position_id, injection_data.stage_info_id, set_constant.Id(),
-         binding_constant.Id(), descriptor_index_id, descriptor_offset_id_, binding_layout_offset.Id()},
+         binding_constant.Id(), descriptor_index_id, descriptor_offset_id, binding_layout_offset.Id()},
         inst_it);
 
     return function_result;
 }
 
-void DescriptorClassGeneralBufferPass::Reset() {
-    descriptor_type_ = nullptr;
-    target_instruction_ = nullptr;
-    descriptor_set_ = 0;
-    descriptor_binding_ = 0;
-    descriptor_index_id_ = 0;
-    descriptor_offset_id_ = 0;
-}
-
-bool DescriptorClassGeneralBufferPass::RequiresInstrumentation(const Function& function, const Instruction& inst, bool pre_pass) {
+bool DescriptorClassGeneralBufferPass::RequiresInstrumentation(const Function& function, const Instruction& inst,
+                                                               InstructionMeta& meta, bool pre_pass) {
     const uint32_t opcode = inst.Opcode();
 
     if (!IsValueIn(spv::Op(opcode), {spv::OpLoad, spv::OpStore, spv::OpAtomicStore, spv::OpAtomicLoad, spv::OpAtomicExchange})) {
@@ -228,12 +221,11 @@ bool DescriptorClassGeneralBufferPass::RequiresInstrumentation(const Function& f
     if (!next_access_chain || next_access_chain->Opcode() != spv::OpAccessChain) {
         return false;
     }
-    access_chain_insts_.clear();  // only clear right before we know we will need again
 
     const Variable* variable = nullptr;
     // We need to walk down possibly multiple chained OpAccessChains or OpCopyObject to get the variable
     while (next_access_chain && next_access_chain->Opcode() == spv::OpAccessChain) {
-        access_chain_insts_.push_back(next_access_chain);
+        meta.access_chain_insts.push_back(next_access_chain);
         const uint32_t access_chain_base_id = next_access_chain->Operand(0);
         variable = module_.type_manager_.FindVariableById(access_chain_base_id);
         if (variable) {
@@ -250,13 +242,13 @@ bool DescriptorClassGeneralBufferPass::RequiresInstrumentation(const Function& f
         return false;
     }
 
-    descriptor_type_ = variable->PointerType(module_.type_manager_);
-    if (!descriptor_type_ || descriptor_type_->spv_type_ == SpvType::kRuntimeArray) {
+    meta.descriptor_type = variable->PointerType(module_.type_manager_);
+    if (!meta.descriptor_type || meta.descriptor_type->spv_type_ == SpvType::kRuntimeArray) {
         return false;  // TODO - Currently we mark these as "bindless"
     }
 
-    const bool is_descriptor_array = descriptor_type_->IsArray();
-    const uint32_t descriptor_id = is_descriptor_array ? descriptor_type_->inst_.Operand(0) : descriptor_type_->Id();
+    const bool is_descriptor_array = meta.descriptor_type->IsArray();
+    const uint32_t descriptor_id = is_descriptor_array ? meta.descriptor_type->inst_.Operand(0) : meta.descriptor_type->Id();
 
     // Check for deprecated storage block form
     if (storage_class == spv::StorageClassUniform) {
@@ -272,34 +264,34 @@ bool DescriptorClassGeneralBufferPass::RequiresInstrumentation(const Function& f
     }
 
     // Grab front() as it will be the "final" type we access
-    const Type* value_type = module_.type_manager_.FindValueTypeById(access_chain_insts_.front()->TypeId());
+    const Type* value_type = module_.type_manager_.FindValueTypeById(meta.access_chain_insts.front()->TypeId());
     if (!value_type) return false;
 
     if (is_descriptor_array) {
         // Because you can't have 2D array of descriptors, the first index of the last accessChain is the descriptor index
-        descriptor_index_id_ = access_chain_insts_.back()->Operand(1);
+        meta.descriptor_index_id = meta.access_chain_insts.back()->Operand(1);
     } else {
         // There is no array of this descriptor, so we essentially have an array of 1
-        descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id();
+        meta.descriptor_index_id = module_.type_manager_.GetConstantZeroUint32().Id();
     }
 
     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);
+                meta.descriptor_set = annotation->Word(3);
             } else if (annotation->Word(2) == spv::DecorationBinding) {
-                descriptor_binding_ = annotation->Word(3);
+                meta.descriptor_binding = annotation->Word(3);
             }
         }
     }
 
-    if (descriptor_set_ >= glsl::kDebugInputBindlessMaxDescSets) {
+    if (meta.descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) {
         module_.InternalWarning(Name(), "Tried to use a descriptor slot over the current max limit");
         return false;
     }
 
     if (unsafe_mode_) {
-        const uint32_t offset = FindLastByteOffset(descriptor_id, is_descriptor_array, access_chain_insts_);
+        const uint32_t offset = FindLastByteOffset(descriptor_id, is_descriptor_array, meta.access_chain_insts);
         // If no offset, its dynamic and ignore completly
         if (offset != 0) {
             if (pre_pass) {
@@ -320,7 +312,7 @@ bool DescriptorClassGeneralBufferPass::RequiresInstrumentation(const Function& f
     }
 
     // Save information to be used to make the Function
-    target_instruction_ = &inst;
+    meta.target_instruction = &inst;
 
     return true;
 }
@@ -341,18 +333,19 @@ bool DescriptorClassGeneralBufferPass::Instrument() {
             auto& block_instructions = (*block_it)->instructions_;
 
             if (unsafe_mode_) {
+                InstructionMeta meta;  // dummy object
                 // Loop the Block once to get the highest offset
                 // Do here before we inject instructions into the block list below
                 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 (!RequiresInstrumentation(*function, *(inst_it->get()), true)) continue;
-                    Reset();
+                    if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, true)) continue;
                 }
             }
 
             for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) {
+                InstructionMeta meta;
                 // Every instruction is analyzed by the specific pass and lets us know if we need to inject a function or not
-                if (!RequiresInstrumentation(*function, *(inst_it->get()), false)) continue;
+                if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, false)) continue;
 
                 if (module_.settings_.max_instrumentations_count != 0 &&
                     instrumentations_count_ >= module_.settings_.max_instrumentations_count) {
@@ -363,13 +356,12 @@ bool DescriptorClassGeneralBufferPass::Instrument() {
                 // 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_->GetPositionIndex();
+                const uint32_t inst_position = meta.target_instruction->GetPositionIndex();
                 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();
+                CreateFunctionCall(**block_it, &inst_it, injection_data, meta);
             }
         }
     }
diff --git a/layers/gpuav/spirv/descriptor_class_general_buffer_pass.h b/layers/gpuav/spirv/descriptor_class_general_buffer_pass.h
index 1d127096739..c685ae5c2b8 100644
--- a/layers/gpuav/spirv/descriptor_class_general_buffer_pass.h
+++ b/layers/gpuav/spirv/descriptor_class_general_buffer_pass.h
@@ -32,9 +32,27 @@ class DescriptorClassGeneralBufferPass : public Pass {
     void PrintDebugInfo() const final;
 
   private:
-    bool RequiresInstrumentation(const Function& function, const Instruction& inst, bool pre_pass);
-    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data);
-    void Reset() final;
+    // This is metadata tied to a single instruction gathered during RequiresInstrumentation() to be used later
+    struct InstructionMeta {
+        const Instruction* target_instruction = nullptr;
+
+        uint32_t descriptor_set = 0;
+        uint32_t descriptor_binding = 0;
+        uint32_t descriptor_index_id = 0;  // index input the descriptor array
+
+        // The Type of the OpVariable that is being accessed
+        const Type* descriptor_type = nullptr;
+
+        // List of OpAccessChains fom the Store/Load down to the OpVariable
+        // The front() will be closet to the exact spot accesssed
+        // The back() will be closest to the OpVariable
+        // (note GLSL will try to always create a single large OpAccessChain)
+        std::vector<const Instruction*> access_chain_insts;
+    };
+
+    bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta, bool pre_pass);
+    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data,
+                                const InstructionMeta& meta);
 
     uint32_t link_function_id = 0;
     uint32_t GetLinkFunctionId();
@@ -43,19 +61,6 @@ class DescriptorClassGeneralBufferPass : public Pass {
     uint32_t FindLastByteOffset(uint32_t descriptor_id, bool is_descriptor_array,
                                 const std::vector<const Instruction*>& access_chain_insts) const;
 
-    // List of OpAccessChains fom the Store/Load down to the OpVariable
-    // The front() will be closet to the exact spot accesssed
-    // The back() will be closest to the OpVariable
-    // (note GLSL will try to always create a single large OpAccessChain)
-    std::vector<const Instruction*> access_chain_insts_;
-    // The Type of the OpVariable that is being accessed
-    const Type* descriptor_type_ = nullptr;
-
-    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;
-
     // If robustBufferAccess is turned on, we can use that to ensure the hardware will handle OOB accesses (in this case it is very
     // "safe" actually)
     uint32_t unsafe_mode_;
diff --git a/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp b/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp
index d85f937def3..226c42d0689 100644
--- a/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp
+++ b/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp
@@ -40,16 +40,16 @@ uint32_t DescriptorClassTexelBufferPass::GetLinkFunctionId() {
 }
 
 uint32_t DescriptorClassTexelBufferPass::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 InjectionData& injection_data, const InstructionMeta& meta) {
+    assert(meta.access_chain_inst && meta.var_inst);
+    const Constant& set_constant = module_.type_manager_.GetConstantUInt32(meta.descriptor_set);
+    const Constant& binding_constant = module_.type_manager_.GetConstantUInt32(meta.descriptor_binding);
+    const uint32_t descriptor_index_id = CastToUint32(meta.descriptor_index_id, block, inst_it);  // might be int32
 
-    const uint32_t opcode = target_instruction_->Opcode();
+    const uint32_t opcode = meta.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 (meta.target_instruction->Length() > image_operand_position) {
+        const uint32_t image_operand_word = meta.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)
         }
@@ -57,9 +57,9 @@ uint32_t DescriptorClassTexelBufferPass::CreateFunctionCall(BasicBlock& block, I
 
     // Use the imageFetch() parameter to decide the offset
     // TODO - This assumes no depth/arrayed/ms from RequiresInstrumentation
-    descriptor_offset_id_ = CastToUint32(target_instruction_->Operand(1), block, inst_it);
+    const uint32_t descriptor_offset_id = CastToUint32(meta.target_instruction->Operand(1), block, inst_it);
 
-    BindingLayout binding_layout = module_.set_index_to_bindings_layout_lut_[descriptor_set_][descriptor_binding_];
+    BindingLayout binding_layout = module_.set_index_to_bindings_layout_lut_[meta.descriptor_set][meta.descriptor_binding];
     const Constant& binding_layout_offset = module_.type_manager_.GetConstantUInt32(binding_layout.start);
 
     const uint32_t function_result = module_.TakeNextId();
@@ -69,23 +69,14 @@ uint32_t DescriptorClassTexelBufferPass::CreateFunctionCall(BasicBlock& block, I
     block.CreateInstruction(
         spv::OpFunctionCall,
         {bool_type, function_result, function_def, injection_data.inst_position_id, injection_data.stage_info_id, set_constant.Id(),
-         binding_constant.Id(), descriptor_index_id, descriptor_offset_id_, binding_layout_offset.Id()},
+         binding_constant.Id(), descriptor_index_id, descriptor_offset_id, binding_layout_offset.Id()},
         inst_it);
 
     return function_result;
 }
 
-void DescriptorClassTexelBufferPass::Reset() {
-    access_chain_inst_ = nullptr;
-    var_inst_ = nullptr;
-    target_instruction_ = nullptr;
-    descriptor_set_ = 0;
-    descriptor_binding_ = 0;
-    descriptor_index_id_ = 0;
-    descriptor_offset_id_ = 0;
-}
-
-bool DescriptorClassTexelBufferPass::RequiresInstrumentation(const Function& function, const Instruction& inst) {
+bool DescriptorClassTexelBufferPass::RequiresInstrumentation(const Function& function, const Instruction& inst,
+                                                             InstructionMeta& meta) {
     const uint32_t opcode = inst.Opcode();
 
     if (opcode != spv::OpImageFetch && opcode != spv::OpImageWrite && opcode != spv::OpImageRead) {
@@ -93,9 +84,9 @@ bool DescriptorClassTexelBufferPass::RequiresInstrumentation(const Function& fun
     }
     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());
+    meta.image_inst = function.FindInstruction(inst.Word(image_word));
+    if (!meta.image_inst) return false;
+    const Type* image_type = module_.type_manager_.FindTypeById(meta.image_inst->TypeId());
     if (!image_type) return false;
 
     const uint32_t dim = image_type->inst_.Operand(1);
@@ -111,7 +102,7 @@ bool DescriptorClassTexelBufferPass::RequiresInstrumentation(const Function& fun
     }
 
     // walk down to get the actual load
-    const Instruction* load_inst = image_inst_;
+    const Instruction* load_inst = meta.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));
@@ -120,56 +111,56 @@ bool DescriptorClassTexelBufferPass::RequiresInstrumentation(const Function& fun
         return false;  // TODO: Handle additional possibilities?
     }
 
-    var_inst_ = function.FindInstruction(load_inst->Operand(0));
-    if (!var_inst_) {
+    meta.var_inst = function.FindInstruction(load_inst->Operand(0));
+    if (!meta.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;
+        meta.var_inst = global_var ? &global_var->inst_ : nullptr;
     }
-    if (!var_inst_ || (var_inst_->Opcode() != spv::OpAccessChain && var_inst_->Opcode() != spv::OpVariable)) {
+    if (!meta.var_inst || (meta.var_inst->Opcode() != spv::OpAccessChain && meta.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_;
+    meta.access_chain_inst = meta.var_inst;
 
-    if (var_inst_->Opcode() == spv::OpAccessChain) {
-        descriptor_index_id_ = var_inst_->Operand(1);
+    if (meta.var_inst->Opcode() == spv::OpAccessChain) {
+        meta.descriptor_index_id = meta.var_inst->Operand(1);
 
-        if (var_inst_->Length() > 5) {
+        if (meta.var_inst->Length() > 5) {
             module_.InternalError(Name(), "OpAccessChain has more than 1 indexes. 2D Texel Buffers not supported");
             return false;
         }
 
-        const Variable* variable = module_.type_manager_.FindVariableById(var_inst_->Operand(0));
+        const Variable* variable = module_.type_manager_.FindVariableById(meta.var_inst->Operand(0));
         if (!variable) {
             module_.InternalError(Name(), "OpAccessChain base is not a variable");
             return false;
         }
-        var_inst_ = &variable->inst_;
+        meta.var_inst = &variable->inst_;
     } else {
         // There is no array of this descriptor, so we essentially have an array of 1
-        descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id();
+        meta.descriptor_index_id = module_.type_manager_.GetConstantZeroUint32().Id();
     }
 
-    uint32_t variable_id = var_inst_->ResultId();
+    uint32_t variable_id = meta.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);
+                meta.descriptor_set = annotation->Word(3);
             } else if (annotation->Word(2) == spv::DecorationBinding) {
-                descriptor_binding_ = annotation->Word(3);
+                meta.descriptor_binding = annotation->Word(3);
             }
         }
     }
 
-    if (descriptor_set_ >= glsl::kDebugInputBindlessMaxDescSets) {
+    if (meta.descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) {
         module_.InternalWarning(Name(), "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;
+    meta.target_instruction = &inst;
 
     return true;
 }
@@ -189,8 +180,9 @@ bool DescriptorClassTexelBufferPass::Instrument() {
             }
             auto& block_instructions = (*block_it)->instructions_;
             for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) {
+                InstructionMeta meta;
                 // Every instruction is analyzed by the specific pass and lets us know if we need to inject a function or not
-                if (!RequiresInstrumentation(*function, *(inst_it->get()))) continue;
+                if (!RequiresInstrumentation(*function, *(inst_it->get()), meta)) continue;
 
                 if (module_.settings_.max_instrumentations_count != 0 &&
                     instrumentations_count_ >= module_.settings_.max_instrumentations_count) {
@@ -201,13 +193,12 @@ bool DescriptorClassTexelBufferPass::Instrument() {
                 // 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_->GetPositionIndex();
+                const uint32_t inst_position = meta.target_instruction->GetPositionIndex();
                 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();
+                CreateFunctionCall(**block_it, &inst_it, injection_data, meta);
             }
         }
     }
diff --git a/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h b/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h
index abda943c039..2786e353a22 100644
--- a/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h
+++ b/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h
@@ -31,21 +31,24 @@ class DescriptorClassTexelBufferPass : public Pass {
     void PrintDebugInfo() const final;
 
   private:
-    bool RequiresInstrumentation(const Function& function, const Instruction& inst);
-    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data);
-    void Reset() final;
+    // This is metadata tied to a single instruction gathered during RequiresInstrumentation() to be used later
+    struct InstructionMeta {
+        const Instruction* target_instruction = nullptr;
+        const Instruction* access_chain_inst = nullptr;
+        const Instruction* var_inst = nullptr;
+        const Instruction* image_inst = nullptr;
+
+        uint32_t descriptor_set = 0;
+        uint32_t descriptor_binding = 0;
+        uint32_t descriptor_index_id = 0;  // index input the descriptor array
+    };
+
+    bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta);
+    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data,
+                                const InstructionMeta& meta);
 
     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_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
diff --git a/layers/gpuav/spirv/descriptor_indexing_oob_pass.cpp b/layers/gpuav/spirv/descriptor_indexing_oob_pass.cpp
index 4b8511ae6c9..297e7a068e5 100644
--- a/layers/gpuav/spirv/descriptor_indexing_oob_pass.cpp
+++ b/layers/gpuav/spirv/descriptor_indexing_oob_pass.cpp
@@ -28,7 +28,7 @@ namespace gpuav {
 namespace spirv {
 
 // By appending the LinkInfo, it will attempt at linking stage to add the function.
-uint32_t DescriptorIndexingOOBPass::GetLinkFunctionId() {
+uint32_t DescriptorIndexingOOBPass::GetLinkFunctionId(bool is_combined_image_sampler) {
     // This pass has 2 variations of GLSL we can pull in. Non-Bindless is simpler and we want to use when possible
     static LinkInfo link_info_bindless = {instrumentation_descriptor_indexing_oob_bindless_comp,
                                           instrumentation_descriptor_indexing_oob_bindless_comp_size, 0,
@@ -52,7 +52,7 @@ uint32_t DescriptorIndexingOOBPass::GetLinkFunctionId() {
             module_.link_info_.push_back(link_info);
         }
         link_id = link_function_id_non_bindless_;
-    } else if (is_combined_image_sampler_) {
+    } else if (is_combined_image_sampler) {
         if (link_function_id_bindless_combined_image_sampler_ == 0) {
             link_function_id_bindless_combined_image_sampler_ = module_.TakeNextId();
             LinkInfo& link_info = link_info_bindless_combined_image_sampler;
@@ -73,24 +73,24 @@ uint32_t DescriptorIndexingOOBPass::GetLinkFunctionId() {
 }
 
 uint32_t DescriptorIndexingOOBPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it,
-                                                       const InjectionData& injection_data) {
-    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 InjectionData& injection_data, const InstructionMeta& meta) {
+    const Constant& set_constant = module_.type_manager_.GetConstantUInt32(meta.descriptor_set);
+    const Constant& binding_constant = module_.type_manager_.GetConstantUInt32(meta.descriptor_binding);
+    const uint32_t descriptor_index_id = CastToUint32(meta.descriptor_index_id, block, inst_it);  // might be int32
 
-    if (image_inst_) {
-        const uint32_t opcode = target_instruction_->Opcode();
+    if (meta.image_inst) {
+        const uint32_t opcode = meta.target_instruction->Opcode();
         if (opcode != spv::OpImageRead && opcode != spv::OpImageFetch && opcode != spv::OpImageWrite) {
             // if not a direct read/write/fetch, will be a OpSampledImage
             // "All OpSampledImage instructions must be in the same block in which their Result <id> are consumed"
             // the simple way around this is to add a OpCopyObject to be consumed by the target instruction
-            uint32_t image_id = target_instruction_->Operand(0);
+            uint32_t image_id = meta.target_instruction->Operand(0);
             const Instruction* sampled_image_inst = block.function_.FindInstruction(image_id);
             // TODO - Add tests to understand what else can be here other then OpSampledImage
             if (sampled_image_inst->Opcode() == spv::OpSampledImage) {
                 const uint32_t type_id = sampled_image_inst->TypeId();
                 const uint32_t copy_id = module_.TakeNextId();
-                const_cast<Instruction*>(target_instruction_)->ReplaceOperandId(image_id, copy_id);
+                const_cast<Instruction*>(meta.target_instruction)->ReplaceOperandId(image_id, copy_id);
 
                 // incase the OpSampledImage is shared, copy the previous OpCopyObject
                 auto copied = copy_object_map_.find(image_id);
@@ -106,12 +106,12 @@ uint32_t DescriptorIndexingOOBPass::CreateFunctionCall(BasicBlock& block, Instru
         }
     }
 
-    BindingLayout binding_layout = module_.set_index_to_bindings_layout_lut_[descriptor_set_][descriptor_binding_];
+    BindingLayout binding_layout = module_.set_index_to_bindings_layout_lut_[meta.descriptor_set][meta.descriptor_binding];
     const Constant& binding_layout_size = module_.type_manager_.GetConstantUInt32(binding_layout.count);
     const Constant& binding_layout_offset = module_.type_manager_.GetConstantUInt32(binding_layout.start);
 
     uint32_t function_result = module_.TakeNextId();
-    const uint32_t function_def = GetLinkFunctionId();
+    const uint32_t function_def = GetLinkFunctionId(meta.is_combined_image_sampler);
     const uint32_t bool_type = module_.type_manager_.GetTypeBool().Id();
 
     block.CreateInstruction(
@@ -124,16 +124,17 @@ uint32_t DescriptorIndexingOOBPass::CreateFunctionCall(BasicBlock& block, Instru
     //     bool valid_image = inst_descriptor_indexing_oob(image);
     //     bool valid_sampler = inst_descriptor_indexing_oob(sampler);
     //     bool valid_both = image_valid && sampler_valid;
-    if (sampler_var_inst_) {
+    if (meta.sampler_var_inst) {
         const uint32_t valid_image = function_result;
         const uint32_t valid_sampler = module_.TakeNextId();
 
-        const Constant& sampler_set_constant = module_.type_manager_.GetConstantUInt32(sampler_descriptor_set_);
-        const Constant& sampler_binding_constant = module_.type_manager_.GetConstantUInt32(sampler_descriptor_binding_);
-        const uint32_t sampler_descriptor_index_id = CastToUint32(sampler_descriptor_index_id_, block, inst_it);  // might be int32
+        const Constant& sampler_set_constant = module_.type_manager_.GetConstantUInt32(meta.sampler_descriptor_set);
+        const Constant& sampler_binding_constant = module_.type_manager_.GetConstantUInt32(meta.sampler_descriptor_binding);
+        const uint32_t sampler_descriptor_index_id =
+            CastToUint32(meta.sampler_descriptor_index_id, block, inst_it);  // might be int32
 
         BindingLayout sampler_binding_layout =
-            module_.set_index_to_bindings_layout_lut_[sampler_descriptor_set_][sampler_descriptor_binding_];
+            module_.set_index_to_bindings_layout_lut_[meta.sampler_descriptor_set][meta.sampler_descriptor_binding];
         const Constant& sampler_binding_layout_size = module_.type_manager_.GetConstantUInt32(sampler_binding_layout.count);
         const Constant& sampler_binding_layout_offset = module_.type_manager_.GetConstantUInt32(sampler_binding_layout.start);
 
@@ -152,18 +153,7 @@ uint32_t DescriptorIndexingOOBPass::CreateFunctionCall(BasicBlock& block, Instru
 
 void DescriptorIndexingOOBPass::NewBlock(const BasicBlock&) { block_instrumented_table_.clear(); }
 
-void DescriptorIndexingOOBPass::Reset() {
-    var_inst_ = nullptr;
-    sampler_var_inst_ = nullptr;
-    is_combined_image_sampler_ = false;
-    image_inst_ = nullptr;
-    target_instruction_ = nullptr;
-    descriptor_set_ = 0;
-    descriptor_binding_ = 0;
-    descriptor_index_id_ = 0;
-}
-
-bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function, const Instruction& inst) {
+bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) {
     const uint32_t opcode = inst.Opcode();
 
     bool array_found = false;
@@ -187,7 +177,7 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
         if (!variable) {
             return false;
         }
-        var_inst_ = &variable->inst_;
+        meta.var_inst = &variable->inst_;
 
         const Type* pointer_type = variable->PointerType(module_.type_manager_);
         if (!pointer_type) {
@@ -198,10 +188,10 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
         const bool non_empty_access_chain = access_chain_inst && access_chain_inst->Length() >= 5;
         if (pointer_type->IsArray() && non_empty_access_chain) {
             array_found = true;
-            descriptor_index_id_ = access_chain_inst->Operand(1);
+            meta.descriptor_index_id = access_chain_inst->Operand(1);
         } else {
             // There is no array of this descriptor, so we essentially have an array of 1
-            descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id();
+            meta.descriptor_index_id = module_.type_manager_.GetConstantZeroUint32().Id();
         }
     } else if (opcode == spv::OpLoad || opcode == spv::OpStore || AtomicOperation(opcode)) {
         // Buffer and Buffer Atomics and Storage Images
@@ -221,7 +211,7 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
             return false;
         }
 
-        var_inst_ = &variable->inst_;
+        meta.var_inst = &variable->inst_;
 
         const uint32_t storage_class = variable->StorageClass();
         if (storage_class == spv::StorageClassUniformConstant) {
@@ -240,10 +230,10 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
 
         if (pointer_type->IsArray()) {
             array_found = true;
-            descriptor_index_id_ = access_chain_inst->Operand(1);
+            meta.descriptor_index_id = access_chain_inst->Operand(1);
         } else {
             // There is no array of this descriptor, so we essentially have an array of 1
-            descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id();
+            meta.descriptor_index_id = module_.type_manager_.GetConstantZeroUint32().Id();
         }
     } else {
         // sampled image (non-atomic)
@@ -263,8 +253,8 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
             return false;  // Don't deal with the access directly
         }
 
-        image_inst_ = function.FindInstruction(inst.Word(image_word));
-        const Instruction* load_inst = image_inst_;
+        meta.image_inst = function.FindInstruction(inst.Word(image_word));
+        const Instruction* load_inst = meta.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));
@@ -275,39 +265,39 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
 
         // If we can't find a seperate sampler, and non sampled images are check elsewhere, we know this is actually a combined
         // image sampler
-        is_combined_image_sampler_ = sampler_load_inst == nullptr;
+        meta.is_combined_image_sampler = sampler_load_inst == nullptr;
 
         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_) {
+        meta.var_inst = function.FindInstruction(load_inst->Operand(0));
+        if (!meta.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;
+            meta.var_inst = global_var ? &global_var->inst_ : nullptr;
         }
-        if (!var_inst_ || (var_inst_->Opcode() != spv::OpAccessChain && var_inst_->Opcode() != spv::OpVariable)) {
+        if (!meta.var_inst || (meta.var_inst->Opcode() != spv::OpAccessChain && meta.var_inst->Opcode() != spv::OpVariable)) {
             return false;
         }
 
-        if (var_inst_->Opcode() == spv::OpAccessChain) {
+        if (meta.var_inst->Opcode() == spv::OpAccessChain) {
             array_found = true;
-            descriptor_index_id_ = var_inst_->Operand(1);
+            meta.descriptor_index_id = meta.var_inst->Operand(1);
 
-            if (var_inst_->Length() > 5) {
+            if (meta.var_inst->Length() > 5) {
                 module_.InternalError(Name(), "OpAccessChain has more than 1 indexes");
                 return false;
             }
 
-            const Variable* variable = module_.type_manager_.FindVariableById(var_inst_->Operand(0));
+            const Variable* variable = module_.type_manager_.FindVariableById(meta.var_inst->Operand(0));
             if (!variable) {
                 module_.InternalError(Name(), "OpAccessChain base is not a variable");
                 return false;
             }
-            var_inst_ = &variable->inst_;
+            meta.var_inst = &variable->inst_;
         } else {
-            descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id();
+            meta.descriptor_index_id = module_.type_manager_.GetConstantZeroUint32().Id();
         }
     }
 
@@ -316,19 +306,19 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
         return false;
     }
 
-    assert(var_inst_);
-    uint32_t variable_id = var_inst_->ResultId();
+    assert(meta.var_inst);
+    uint32_t variable_id = meta.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);
+                meta.descriptor_set = annotation->Word(3);
             } else if (annotation->Word(2) == spv::DecorationBinding) {
-                descriptor_binding_ = annotation->Word(3);
+                meta.descriptor_binding = annotation->Word(3);
             }
         }
     }
 
-    if (descriptor_set_ >= glsl::kDebugInputBindlessMaxDescSets) {
+    if (meta.descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) {
         module_.InternalWarning(Name(), "Tried to use a descriptor slot over the current max limit");
         return false;
     }
@@ -336,13 +326,13 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
     if (module_.settings_.unsafe_mode) {
         auto variable_found_it = block_instrumented_table_.find(variable_id);
         if (variable_found_it == block_instrumented_table_.end()) {
-            block_instrumented_table_[variable_id] = {descriptor_index_id_};
+            block_instrumented_table_[variable_id] = {meta.descriptor_index_id};
         } else {
             vvl::unordered_set<uint32_t>& descriptor_index_set = variable_found_it->second;
-            if (descriptor_index_set.find(descriptor_index_id_) != descriptor_index_set.end()) {
+            if (descriptor_index_set.find(meta.descriptor_index_id) != descriptor_index_set.end()) {
                 return false;  // Already instrumented, can skip
             } else {
-                descriptor_index_set.emplace(descriptor_index_id_);
+                descriptor_index_set.emplace(meta.descriptor_index_id);
             }
         }
     }
@@ -350,54 +340,54 @@ bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function
     // When using a SAMPLED_IMAGE and SAMPLER, they are accessed together so we need check for 2 descriptors at the same time
     // TODO - This is currently 95% the same logic as above, find a way to combine it
     if (sampler_load_inst && sampler_load_inst->Opcode() == spv::OpLoad) {
-        sampler_var_inst_ = function.FindInstruction(sampler_load_inst->Operand(0));
-        if (!sampler_var_inst_) {
+        meta.sampler_var_inst = function.FindInstruction(sampler_load_inst->Operand(0));
+        if (!meta.sampler_var_inst) {
             // can be a global variable
             const Variable* global_var = module_.type_manager_.FindVariableById(sampler_load_inst->Operand(0));
-            sampler_var_inst_ = global_var ? &global_var->inst_ : nullptr;
+            meta.sampler_var_inst = global_var ? &global_var->inst_ : nullptr;
         }
-        if (!sampler_var_inst_ ||
-            (sampler_var_inst_->Opcode() != spv::OpAccessChain && sampler_var_inst_->Opcode() != spv::OpVariable)) {
+        if (!meta.sampler_var_inst ||
+            (meta.sampler_var_inst->Opcode() != spv::OpAccessChain && meta.sampler_var_inst->Opcode() != spv::OpVariable)) {
             return false;
         }
 
-        if (sampler_var_inst_->Opcode() == spv::OpAccessChain) {
+        if (meta.sampler_var_inst->Opcode() == spv::OpAccessChain) {
             array_found = true;
-            sampler_descriptor_index_id_ = sampler_var_inst_->Operand(1);
+            meta.sampler_descriptor_index_id = meta.sampler_var_inst->Operand(1);
 
-            if (sampler_var_inst_->Length() > 5) {
+            if (meta.sampler_var_inst->Length() > 5) {
                 module_.InternalError(Name(), "Sampler OpAccessChain has more than 1 indexes");
                 return false;
             }
 
-            const Variable* variable = module_.type_manager_.FindVariableById(sampler_var_inst_->Operand(0));
+            const Variable* variable = module_.type_manager_.FindVariableById(meta.sampler_var_inst->Operand(0));
             if (!variable) {
                 module_.InternalError(Name(), "Sampler OpAccessChain base is not a variable");
                 return false;
             }
-            sampler_var_inst_ = &variable->inst_;
+            meta.sampler_var_inst = &variable->inst_;
         } else {
-            sampler_descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id();
+            meta.sampler_descriptor_index_id = module_.type_manager_.GetConstantZeroUint32().Id();
         }
 
-        variable_id = sampler_var_inst_->ResultId();
+        variable_id = meta.sampler_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) {
-                    sampler_descriptor_set_ = annotation->Word(3);
+                    meta.sampler_descriptor_set = annotation->Word(3);
                 } else if (annotation->Word(2) == spv::DecorationBinding) {
-                    sampler_descriptor_binding_ = annotation->Word(3);
+                    meta.sampler_descriptor_binding = annotation->Word(3);
                 }
             }
         }
 
-        if (sampler_descriptor_set_ >= glsl::kDebugInputBindlessMaxDescSets) {
+        if (meta.sampler_descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) {
             module_.InternalWarning(Name(), "Sampler 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;
+    meta.target_instruction = &inst;
 
     return true;
 }
diff --git a/layers/gpuav/spirv/descriptor_indexing_oob_pass.h b/layers/gpuav/spirv/descriptor_indexing_oob_pass.h
index 4fcafc6b530..0289ff971af 100644
--- a/layers/gpuav/spirv/descriptor_indexing_oob_pass.h
+++ b/layers/gpuav/spirv/descriptor_indexing_oob_pass.h
@@ -15,7 +15,6 @@
 #pragma once
 
 #include <stdint.h>
-#include <vector>
 #include "containers/custom_containers.h"
 #include "inject_conditional_function_pass.h"
 
@@ -33,28 +32,14 @@ class DescriptorIndexingOOBPass : public InjectConditionalFunctionPass {
     void NewBlock(const BasicBlock& block) override;
 
   private:
-    bool RequiresInstrumentation(const Function& function, const Instruction& inst) final;
-    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data) final;
-    void Reset() final;
+    bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) final;
+    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data,
+                                const InstructionMeta& meta) final;
 
     uint32_t link_function_id_bindless_ = 0;
     uint32_t link_function_id_bindless_combined_image_sampler_ = 0;
     uint32_t link_function_id_non_bindless_ = 0;
-    uint32_t GetLinkFunctionId();
-
-    const Instruction* var_inst_ = nullptr;
-    const Instruction* image_inst_ = nullptr;
-
-    uint32_t descriptor_set_ = 0;
-    uint32_t descriptor_binding_ = 0;
-    uint32_t descriptor_index_id_ = 0;
-
-    bool is_combined_image_sampler_ = false;
-    // Duplicate values if dealing with SAMPLED_IMAGE and SAMPLER together
-    const Instruction* sampler_var_inst_ = nullptr;
-    uint32_t sampler_descriptor_set_ = 0;
-    uint32_t sampler_descriptor_binding_ = 0;
-    uint32_t sampler_descriptor_index_id_ = 0;
+    uint32_t GetLinkFunctionId(bool is_combined_image_sampler);
 
     // < original ID, new CopyObject ID >
     vvl::unordered_map<uint32_t, uint32_t> copy_object_map_;
diff --git a/layers/gpuav/spirv/inject_conditional_function_pass.cpp b/layers/gpuav/spirv/inject_conditional_function_pass.cpp
index 57f860724f5..f93c60e6a8d 100644
--- a/layers/gpuav/spirv/inject_conditional_function_pass.cpp
+++ b/layers/gpuav/spirv/inject_conditional_function_pass.cpp
@@ -22,7 +22,7 @@ namespace spirv {
 InjectConditionalFunctionPass::InjectConditionalFunctionPass(Module& module) : Pass(module) { module.use_bda_ = true; }
 
 BasicBlockIt InjectConditionalFunctionPass::InjectFunction(Function* function, BasicBlockIt block_it, InstructionIt inst_it,
-                                                           const InjectionData& injection_data) {
+                                                           const InjectionData& injection_data, const InstructionMeta& meta) {
     // We turn the block into 4 separate blocks
     block_it = function->InsertNewBlock(block_it);
     block_it = function->InsertNewBlock(block_it);
@@ -104,13 +104,11 @@ BasicBlockIt InjectConditionalFunctionPass::InjectFunction(Function* function, B
     original_block.instructions_.erase(inst_it, original_block.instructions_.end());
 
     // Go back to original Block and add function call and branch from the bool result
-    const uint32_t function_result = CreateFunctionCall(original_block, nullptr, injection_data);
+    const uint32_t function_result = CreateFunctionCall(original_block, nullptr, injection_data, meta);
 
     original_block.CreateInstruction(spv::OpSelectionMerge, {merge_block_label, spv::SelectionControlMaskNone});
     original_block.CreateInstruction(spv::OpBranchConditional, {function_result, valid_block_label, invalid_block_label});
 
-    Reset();
-
     return block_it;
 }
 
@@ -126,8 +124,9 @@ bool InjectConditionalFunctionPass::Instrument() {
             NewBlock(**block_it);
 
             for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) {
+                InstructionMeta meta;
                 // Every instruction is analyzed by the specific pass and lets us know if we need to inject a function or not
-                if (!RequiresInstrumentation(*function, *(inst_it->get()))) {
+                if (!RequiresInstrumentation(*function, *(inst_it->get()), meta)) {
                     // TODO - This should be cleaned up then having it injected here
                     // we can have a situation where the incoming SPIR-V looks like
                     // %a = OpSampledImage %type %image %sampler
@@ -157,11 +156,11 @@ bool InjectConditionalFunctionPass::Instrument() {
                 // 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_->GetPositionIndex();
+                const uint32_t inst_position = meta.target_instruction->GetPositionIndex();
                 auto inst_position_constant = module_.type_manager_.CreateConstantUInt32(inst_position);
                 injection_data.inst_position_id = inst_position_constant.Id();
 
-                block_it = InjectFunction(function.get(), block_it, inst_it, injection_data);
+                block_it = InjectFunction(function.get(), block_it, inst_it, injection_data, meta);
                 // will start searching again from newly split merge block
                 block_it--;
                 break;
diff --git a/layers/gpuav/spirv/inject_conditional_function_pass.h b/layers/gpuav/spirv/inject_conditional_function_pass.h
index 7376ba15ce7..ec5f4d42320 100644
--- a/layers/gpuav/spirv/inject_conditional_function_pass.h
+++ b/layers/gpuav/spirv/inject_conditional_function_pass.h
@@ -51,15 +51,43 @@ class InjectConditionalFunctionPass : public Pass {
   protected:
     InjectConditionalFunctionPass(Module& module);
 
+    // This is metadata tied to a single instruction gathered during RequiresInstrumentation() to be used later
+    // TODO - Currently this is shared between the various children parents of InjectConditionalFunctionPass and we should refactor
+    // InjectConditionalFunctionPass to have each class manage their looping of functions/blocks so they can only use their own
+    // variables
+    struct InstructionMeta {
+        const Instruction* target_instruction = nullptr;
+
+        // BufferDeviceAddressPass
+        // ---
+        uint32_t alignment_literal = 0;
+        uint32_t type_length = 0;
+
+        // DescriptorIndexingOOBPass
+        // ---
+        const Instruction* var_inst = nullptr;
+        const Instruction* image_inst = nullptr;
+        uint32_t descriptor_set = 0;
+        uint32_t descriptor_binding = 0;
+        uint32_t descriptor_index_id = 0;
+        bool is_combined_image_sampler = false;
+        // Duplicate values if dealing with SAMPLED_IMAGE and SAMPLER together
+        const Instruction* sampler_var_inst = nullptr;
+        uint32_t sampler_descriptor_set = 0;
+        uint32_t sampler_descriptor_binding = 0;
+        uint32_t sampler_descriptor_index_id = 0;
+    };
+
     BasicBlockIt InjectFunction(Function* function, BasicBlockIt block_it, InstructionIt inst_it,
-                                const InjectionData& injection_data);
+                                const InjectionData& injection_data, const InstructionMeta& meta);
 
     // Each pass decides if the instruction should needs to have its function check injected
-    virtual bool RequiresInstrumentation(const Function& function, const Instruction& inst) = 0;
+    virtual bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) = 0;
     // A callback from the function injection logic.
     // Each pass creates a OpFunctionCall and returns its result id.
     // If |inst_it| is not null, it will update it to instruction post OpFunctionCall
-    virtual uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data) = 0;
+    virtual uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data,
+                                        const InstructionMeta& meta) = 0;
 
     // Optional notification that a new block is being passed
     virtual void NewBlock(const BasicBlock&){};
diff --git a/layers/gpuav/spirv/inject_function_pass.cpp b/layers/gpuav/spirv/inject_function_pass.cpp
deleted file mode 100644
index 99752576c84..00000000000
--- a/layers/gpuav/spirv/inject_function_pass.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (c) 2024-2025 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 "inject_function_pass.h"
-#include "module.h"
-
-namespace gpuav {
-namespace spirv {
-
-InjectFunctionPass::InjectFunctionPass(Module& module) : Pass(module) { module.use_bda_ = true; }
-
-bool InjectFunctionPass::Instrument() {
-    // Can safely loop function list as there is no injecting of new Functions until linking time
-    for (const auto& function : module_.functions_) {
-        if (function->instrumentation_added_) continue;
-        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 (!RequiresInstrumentation(*function, *(inst_it->get()))) continue;
-
-                if (module_.settings_.max_instrumentations_count != 0 &&
-                    instrumentations_count_ >= module_.settings_.max_instrumentations_count) {
-                    return true;  // hit limit
-                }
-                instrumentations_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_->GetPositionIndex();
-                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 instrumentations_count_ != 0;
-}
-
-}  // namespace spirv
-}  // namespace gpuav
\ No newline at end of file
diff --git a/layers/gpuav/spirv/inject_function_pass.h b/layers/gpuav/spirv/inject_function_pass.h
deleted file mode 100644
index 520744200c3..00000000000
--- a/layers/gpuav/spirv/inject_function_pass.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright (c) 2024-2025 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 "pass.h"
-
-namespace gpuav {
-namespace spirv {
-
-// A type of common pass that will inject a function call and link it up later.
-// We assume through other means (such as robustness) we won't crash on bad values and go
-//     PassFunction(original_value)
-//     value = original_value;
-class InjectFunctionPass : public Pass {
-  public:
-    bool Instrument() final;
-
-  protected:
-    InjectFunctionPass(Module& module);
-
-    // Each pass decides if the instruction should needs to have its function check injected
-    virtual bool RequiresInstrumentation(const Function& function, const Instruction& inst) = 0;
-    // A callback from the function injection logic.
-    // Each pass creates a OpFunctionCall and returns its result id.
-    // If |inst_it| is not null, it will update it to instruction post OpFunctionCall
-    virtual uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data) = 0;
-};
-
-}  // namespace spirv
-}  // namespace gpuav
\ No newline at end of file
diff --git a/layers/gpuav/spirv/pass.cpp b/layers/gpuav/spirv/pass.cpp
index fa51611f5fd..b37cc51a9be 100644
--- a/layers/gpuav/spirv/pass.cpp
+++ b/layers/gpuav/spirv/pass.cpp
@@ -65,12 +65,15 @@ const Variable& Pass::GetBuiltinVariable(uint32_t built_in) {
 
 // To reduce having to load this information everytime we do a OpFunctionCall, instead just create it once per Function block and
 // reference it each time
-uint32_t Pass::GetStageInfo(Function& function, BasicBlockIt target_block_it, InstructionIt& target_inst_it) {
+uint32_t Pass::GetStageInfo(Function& function, BasicBlockIt target_block_it, InstructionIt& out_inst_it) {
     // Cached so only need to compute this once
     if (function.stage_info_id_ != 0) {
         return function.stage_info_id_;
     }
 
+    // Save original for later to restore
+    const Instruction& target_instruction = *out_inst_it->get();
+
     BasicBlock& block = function.GetFirstBlock();
     InstructionIt inst_it = block.GetFirstInjectableInstrution();
 
@@ -191,7 +194,7 @@ uint32_t Pass::GetStageInfo(Function& function, BasicBlockIt target_block_it, In
     // because we are injecting things in the first block, there is a chance we just destroyed the iterator if the target
     // instruction was also in the first block, so need to regain it for the caller
     if ((*target_block_it)->GetLabelId() == block.GetLabelId()) {
-        target_inst_it = FindTargetInstruction(block);
+        out_inst_it = FindTargetInstruction(block, target_instruction);
     }
 
     return function.stage_info_id_;
@@ -476,7 +479,7 @@ uint32_t Pass::GetLastByte(const Type& descriptor_type, const std::vector<const
 }
 
 // Generate code to convert integer id to 32bit, if needed.
-uint32_t Pass::ConvertTo32(uint32_t id, BasicBlock& block, InstructionIt* inst_it) {
+uint32_t Pass::ConvertTo32(uint32_t id, BasicBlock& block, InstructionIt* inst_it) const {
     // Find type doing the indexing into the access chain
     const Type* type = nullptr;
     const Constant* constant = module_.type_manager_.FindConstantById(id);
@@ -508,7 +511,7 @@ uint32_t Pass::ConvertTo32(uint32_t id, BasicBlock& block, InstructionIt* inst_i
 }
 
 // Generate code to cast integer it to 32bit unsigned, if needed.
-uint32_t Pass::CastToUint32(uint32_t id, BasicBlock& block, InstructionIt* inst_it) {
+uint32_t Pass::CastToUint32(uint32_t id, BasicBlock& block, InstructionIt* inst_it) const {
     // Convert value to 32-bit if necessary
     uint32_t int32_id = ConvertTo32(id, block, inst_it);
 
@@ -537,13 +540,13 @@ uint32_t Pass::CastToUint32(uint32_t id, BasicBlock& block, InstructionIt* inst_
     return new_id;  // Return an id to the Uint equivalent.
 }
 
-InstructionIt Pass::FindTargetInstruction(BasicBlock& block) const {
-    const uint32_t target_id = target_instruction_->ResultId();
+InstructionIt Pass::FindTargetInstruction(BasicBlock& block, const Instruction& target_instruction) const {
+    const uint32_t target_id = target_instruction.ResultId();
     for (auto inst_it = block.instructions_.begin(); inst_it != block.instructions_.end(); ++inst_it) {
         // This has to re-loop the entire block to find the instruction, using the ResultID, we can quickly compare
         if ((*inst_it)->ResultId() == target_id) {
             // Things like OpStore will have a result id of zero, so need to do deep instruction comparison
-            if (*(*inst_it) == *target_instruction_) {
+            if (*(*inst_it) == target_instruction) {
                 return inst_it;
             }
         }
diff --git a/layers/gpuav/spirv/pass.h b/layers/gpuav/spirv/pass.h
index 10843ebee44..39bea23dd81 100644
--- a/layers/gpuav/spirv/pass.h
+++ b/layers/gpuav/spirv/pass.h
@@ -49,7 +49,7 @@ class Pass {
     const Variable& GetBuiltinVariable(uint32_t built_in);
 
     // Returns the ID for OpCompositeConstruct it creates
-    uint32_t GetStageInfo(Function& function, BasicBlockIt target_block_it, InstructionIt& target_inst_it);
+    uint32_t GetStageInfo(Function& function, BasicBlockIt target_block_it, InstructionIt& out_inst_it);
 
     const Instruction* GetDecoration(uint32_t id, spv::Decoration decoration) const;
     const Instruction* GetMemberDecoration(uint32_t id, uint32_t member_index, spv::Decoration decoration) const;
@@ -59,20 +59,16 @@ class Pass {
                          InstructionIt* inst_it);
     // Generate SPIR-V needed to help convert things to be uniformly uint32_t
     // If no inst_it is passed in, any new instructions will be added to end of the Block
-    uint32_t ConvertTo32(uint32_t id, BasicBlock& block, InstructionIt* inst_it);
-    uint32_t CastToUint32(uint32_t id, BasicBlock& block, InstructionIt* inst_it);
+    uint32_t ConvertTo32(uint32_t id, BasicBlock& block, InstructionIt* inst_it) const;
+    uint32_t CastToUint32(uint32_t id, BasicBlock& block, InstructionIt* inst_it) const;
 
   protected:
     Pass(Module& module) : module_(module) {}
     Module& module_;
 
-    // clear values between instrumented instructions
-    virtual void Reset() = 0;
-
     // As various things are modifiying the instruction streams, we need to get back to where we were.
     // (normally set in the RequiresInstrumentation call)
-    const Instruction* target_instruction_ = nullptr;
-    InstructionIt FindTargetInstruction(BasicBlock& block) const;
+    InstructionIt FindTargetInstruction(BasicBlock& block, const Instruction& target_instruction) const;
 
     uint32_t instrumentations_count_ = 0;
 };
diff --git a/layers/gpuav/spirv/post_process_descriptor_indexing_pass.cpp b/layers/gpuav/spirv/post_process_descriptor_indexing_pass.cpp
index aecf501cd63..fb2da6861d1 100644
--- a/layers/gpuav/spirv/post_process_descriptor_indexing_pass.cpp
+++ b/layers/gpuav/spirv/post_process_descriptor_indexing_pass.cpp
@@ -38,16 +38,17 @@ uint32_t PostProcessDescriptorIndexingPass::GetLinkFunctionId() {
     return link_function_id;
 }
 
-void PostProcessDescriptorIndexingPass::CreateFunctionCall(BasicBlockIt block_it, InstructionIt* inst_it) {
+void PostProcessDescriptorIndexingPass::CreateFunctionCall(BasicBlockIt block_it, InstructionIt* inst_it,
+                                                           const InstructionMeta& meta) {
     BasicBlock& block = **block_it;
 
-    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 Constant& set_constant = module_.type_manager_.GetConstantUInt32(meta.descriptor_set);
+    const Constant& binding_constant = module_.type_manager_.GetConstantUInt32(meta.descriptor_binding);
+    const uint32_t descriptor_index_id = CastToUint32(meta.descriptor_index_id, block, inst_it);  // might be int32
 
-    BindingLayout binding_layout = module_.set_index_to_bindings_layout_lut_[descriptor_set_][descriptor_binding_];
+    BindingLayout binding_layout = module_.set_index_to_bindings_layout_lut_[meta.descriptor_set][meta.descriptor_binding];
     const Constant& binding_layout_offset = module_.type_manager_.GetConstantUInt32(binding_layout.start);
-    const Constant& variable_id_constant = module_.type_manager_.GetConstantUInt32(variable_id_);
+    const Constant& variable_id_constant = module_.type_manager_.GetConstantUInt32(meta.variable_id);
 
     const uint32_t function_result = module_.TakeNextId();
     const uint32_t function_def = GetLinkFunctionId();
@@ -59,7 +60,8 @@ void PostProcessDescriptorIndexingPass::CreateFunctionCall(BasicBlockIt block_it
                             inst_it);
 }
 
-bool PostProcessDescriptorIndexingPass::RequiresInstrumentation(const Function& function, const Instruction& inst) {
+bool PostProcessDescriptorIndexingPass::RequiresInstrumentation(const Function& function, const Instruction& inst,
+                                                                InstructionMeta& meta) {
     const uint32_t opcode = inst.Opcode();
 
     const Instruction* var_inst = nullptr;
@@ -87,10 +89,10 @@ bool PostProcessDescriptorIndexingPass::RequiresInstrumentation(const Function&
 
         const Type* pointer_type = variable->PointerType(module_.type_manager_);
         if (pointer_type->IsArray()) {
-            descriptor_index_id_ = access_chain_inst->Operand(1);
+            meta.descriptor_index_id = access_chain_inst->Operand(1);
         } else {
             // There is no array of this descriptor, so we essentially have an array of 1
-            descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id();
+            meta.descriptor_index_id = module_.type_manager_.GetConstantZeroUint32().Id();
         }
 
     } else {
@@ -123,7 +125,7 @@ bool PostProcessDescriptorIndexingPass::RequiresInstrumentation(const Function&
         }
 
         if (var_inst->Opcode() == spv::OpAccessChain) {
-            descriptor_index_id_ = var_inst->Operand(1);
+            meta.descriptor_index_id = var_inst->Operand(1);
 
             if (var_inst->Length() > 5) {
                 module_.InternalError(Name(), "OpAccessChain has more than 1 indexes");
@@ -137,47 +139,40 @@ bool PostProcessDescriptorIndexingPass::RequiresInstrumentation(const Function&
             }
             var_inst = &variable->inst_;
         } else {
-            descriptor_index_id_ = module_.type_manager_.GetConstantZeroUint32().Id();
+            meta.descriptor_index_id = module_.type_manager_.GetConstantZeroUint32().Id();
         }
     }
 
     assert(var_inst);
-    variable_id_ = var_inst->ResultId();
+    meta.variable_id = var_inst->ResultId();
     for (const auto& annotation : module_.annotations_) {
-        if (annotation->Opcode() == spv::OpDecorate && annotation->Word(1) == variable_id_) {
+        if (annotation->Opcode() == spv::OpDecorate && annotation->Word(1) == meta.variable_id) {
             if (annotation->Word(2) == spv::DecorationDescriptorSet) {
-                descriptor_set_ = annotation->Word(3);
+                meta.descriptor_set = annotation->Word(3);
             } else if (annotation->Word(2) == spv::DecorationBinding) {
-                descriptor_binding_ = annotation->Word(3);
+                meta.descriptor_binding = annotation->Word(3);
             }
         }
     }
 
-    if (descriptor_set_ >= glsl::kDebugInputBindlessMaxDescSets) {
+    if (meta.descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) {
         module_.InternalWarning(Name(), "Tried to use a descriptor slot over the current max limit");
         return false;
     }
 
-    target_instruction_ = &inst;
+    meta.target_instruction = &inst;
 
     return true;
 }
 
-void PostProcessDescriptorIndexingPass::Reset() {
-    target_instruction_ = nullptr;
-    descriptor_set_ = 0;
-    descriptor_binding_ = 0;
-    descriptor_index_id_ = 0;
-    variable_id_ = 0;
-}
-
 bool PostProcessDescriptorIndexingPass::Instrument() {
     for (const auto& function : module_.functions_) {
         if (function->instrumentation_added_) continue;
         for (auto block_it = function->blocks_.begin(); block_it != function->blocks_.end(); ++block_it) {
             auto& block_instructions = (*block_it)->instructions_;
             for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) {
-                if (!RequiresInstrumentation(*function, *(inst_it->get()))) continue;
+                InstructionMeta meta;
+                if (!RequiresInstrumentation(*function, *(inst_it->get()), meta)) continue;
 
                 if (module_.settings_.max_instrumentations_count != 0 &&
                     instrumentations_count_ >= module_.settings_.max_instrumentations_count) {
@@ -185,8 +180,7 @@ bool PostProcessDescriptorIndexingPass::Instrument() {
                 }
                 instrumentations_count_++;
 
-                CreateFunctionCall(block_it, &inst_it);
-                Reset();
+                CreateFunctionCall(block_it, &inst_it, meta);
             }
         }
     }
diff --git a/layers/gpuav/spirv/post_process_descriptor_indexing_pass.h b/layers/gpuav/spirv/post_process_descriptor_indexing_pass.h
index de4210ac66f..c532481c48a 100644
--- a/layers/gpuav/spirv/post_process_descriptor_indexing_pass.h
+++ b/layers/gpuav/spirv/post_process_descriptor_indexing_pass.h
@@ -31,17 +31,20 @@ class PostProcessDescriptorIndexingPass : public Pass {
     void PrintDebugInfo() const final;
 
   private:
-    bool RequiresInstrumentation(const Function& function, const Instruction& inst);
-    void CreateFunctionCall(BasicBlockIt block_it, InstructionIt* inst_it);
-    void Reset() final;
+    // This is metadata tied to a single instruction gathered during RequiresInstrumentation() to be used later
+    struct InstructionMeta {
+        const Instruction* target_instruction = nullptr;
+        uint32_t descriptor_set = 0;
+        uint32_t descriptor_binding = 0;
+        uint32_t descriptor_index_id = 0;
+        uint32_t variable_id = 0;
+    };
+
+    bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta);
+    void CreateFunctionCall(BasicBlockIt block_it, InstructionIt* inst_it, const InstructionMeta& meta);
 
     uint32_t link_function_id = 0;
     uint32_t GetLinkFunctionId();
-
-    uint32_t descriptor_set_ = 0;
-    uint32_t descriptor_binding_ = 0;
-    uint32_t descriptor_index_id_ = 0;
-    uint32_t variable_id_ = 0;
 };
 
 }  // namespace spirv
diff --git a/layers/gpuav/spirv/ray_query_pass.cpp b/layers/gpuav/spirv/ray_query_pass.cpp
index 78189d75d44..4eb4e7ccecb 100644
--- a/layers/gpuav/spirv/ray_query_pass.cpp
+++ b/layers/gpuav/spirv/ray_query_pass.cpp
@@ -35,16 +35,17 @@ uint32_t RayQueryPass::GetLinkFunctionId() {
     return link_function_id;
 }
 
-uint32_t RayQueryPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data) {
+uint32_t RayQueryPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data,
+                                          const InstructionMeta& meta) {
     const uint32_t function_result = module_.TakeNextId();
     const uint32_t function_def = GetLinkFunctionId();
     const uint32_t bool_type = module_.type_manager_.GetTypeBool().Id();
 
-    const uint32_t ray_flags_id = target_instruction_->Operand(2);
-    const uint32_t ray_origin_id = target_instruction_->Operand(4);
-    const uint32_t ray_tmin_id = target_instruction_->Operand(5);
-    const uint32_t ray_direction_id = target_instruction_->Operand(6);
-    const uint32_t ray_tmax_id = target_instruction_->Operand(7);
+    const uint32_t ray_flags_id = meta.target_instruction->Operand(2);
+    const uint32_t ray_origin_id = meta.target_instruction->Operand(4);
+    const uint32_t ray_tmin_id = meta.target_instruction->Operand(5);
+    const uint32_t ray_direction_id = meta.target_instruction->Operand(6);
+    const uint32_t ray_tmax_id = meta.target_instruction->Operand(7);
 
     block.CreateInstruction(spv::OpFunctionCall,
                             {bool_type, function_result, function_def, injection_data.inst_position_id,
@@ -54,15 +55,13 @@ uint32_t RayQueryPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst
     return function_result;
 }
 
-void RayQueryPass::Reset() { target_instruction_ = nullptr; }
-
-bool RayQueryPass::RequiresInstrumentation(const Function& function, const Instruction& inst) {
+bool RayQueryPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) {
     (void)function;
     const uint32_t opcode = inst.Opcode();
     if (opcode != spv::OpRayQueryInitializeKHR) {
         return false;
     }
-    target_instruction_ = &inst;
+    meta.target_instruction = &inst;
     return true;
 }
 
diff --git a/layers/gpuav/spirv/ray_query_pass.h b/layers/gpuav/spirv/ray_query_pass.h
index 6d57747ab45..af4e2679b53 100644
--- a/layers/gpuav/spirv/ray_query_pass.h
+++ b/layers/gpuav/spirv/ray_query_pass.h
@@ -28,9 +28,9 @@ class RayQueryPass : public InjectConditionalFunctionPass {
     void PrintDebugInfo() const final;
 
   private:
-    bool RequiresInstrumentation(const Function& function, const Instruction& inst) final;
-    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data) final;
-    void Reset() final;
+    bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) final;
+    uint32_t CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InjectionData& injection_data,
+                                const InstructionMeta& meta) final;
 
     uint32_t link_function_id = 0;
     uint32_t GetLinkFunctionId();
diff --git a/layers/gpuav/spirv/vertex_attribute_fetch_oob.cpp b/layers/gpuav/spirv/vertex_attribute_fetch_oob.cpp
index 92fea733f62..e3359bcd1e7 100644
--- a/layers/gpuav/spirv/vertex_attribute_fetch_oob.cpp
+++ b/layers/gpuav/spirv/vertex_attribute_fetch_oob.cpp
@@ -53,7 +53,6 @@ bool VertexAttributeFetchOob::Instrument() {
 
             BasicBlock& first_block = *function->blocks_[0];
             InstructionIt first_injectable_instruction = first_block.GetFirstInjectableInstrution();
-            target_instruction_ = first_injectable_instruction->get();
 
             const uint32_t stage_info_id = GetStageInfo(*function, function->blocks_.begin(), first_injectable_instruction);
 
diff --git a/layers/gpuav/spirv/vertex_attribute_fetch_oob.h b/layers/gpuav/spirv/vertex_attribute_fetch_oob.h
index 0e9ad0bcba4..a94a1ae4694 100644
--- a/layers/gpuav/spirv/vertex_attribute_fetch_oob.h
+++ b/layers/gpuav/spirv/vertex_attribute_fetch_oob.h
@@ -1,6 +1,6 @@
-/* Copyright (c) 2018-2024 The Khronos Group Inc.
- * Copyright (c) 2018-2024 Valve Corporation
- * Copyright (c) 2018-2024 LunarG, Inc.
+/* Copyright (c) 2025 The Khronos Group Inc.
+ * Copyright (c) 2025 Valve Corporation
+ * Copyright (c) 2025 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@ class VertexAttributeFetchOob : public Pass {
 
   private:
     uint32_t GetLinkFunctionId();
-    void Reset() final {}
 
     uint32_t link_function_id = 0;
     bool instrumentation_performed = false;


Reviews:
user: login: arno-lunarg
body: One thing regarding how `meta` is used needs to be fixed, but otherwise nice change, functional programming > oop
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T14:07:25Z
user: login: arno-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T14:12:52Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T14:14:19Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T14:18:10Z

Review comments:
diff_hunk: @@ -345,14 +341,14 @@ bool DescriptorClassGeneralBufferPass::Instrument() {
                 // Do here before we inject instructions into the block list below
                 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 (!RequiresInstrumentation(*function, *(inst_it->get()), true)) continue;
-                    Reset();
+                    if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, true)) continue;
path: layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
user: login: arno-lunarg
body: Looks like `meta` should be declared at this loop level?
=> if `not RequiresInstrumentation`, meta is not modified, and we directly explore the next instruction
=> if it does, `meta` is supposedly written in `RequiresInstrumentation` but then is immediately reset.

Well actually writing that I realize we just don't need `meta` here, it is a dummy object?
created_at: 2025-03-13T14:05:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -345,14 +341,14 @@ bool DescriptorClassGeneralBufferPass::Instrument() {
                 // Do here before we inject instructions into the block list below
                 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 (!RequiresInstrumentation(*function, *(inst_it->get()), true)) continue;
-                    Reset();
+                    if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, true)) continue;
+                    meta.Reset();
                 }
             }
 
             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 (!RequiresInstrumentation(*function, *(inst_it->get()), false)) continue;
+                if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, false)) continue;
path: layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
user: login: arno-lunarg
body: Same, have `meta` be declared at the top of this loop, and then also no need for an explicit `Reset` at the end of it
created_at: 2025-03-13T14:06:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -345,14 +341,14 @@ bool DescriptorClassGeneralBufferPass::Instrument() {
                 // Do here before we inject instructions into the block list below
                 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 (!RequiresInstrumentation(*function, *(inst_it->get()), true)) continue;
-                    Reset();
+                    if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, true)) continue;
+                    meta.Reset();
                 }
             }
 
             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 (!RequiresInstrumentation(*function, *(inst_it->get()), false)) continue;
+                if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, false)) continue;
path: layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
user: login: arno-lunarg
body: Actually you should just return a `meta` object, not pass it around like that. You could have `RequiresInstrumentation` return a `std::optional<InstrumentationMeta>`, that's more functional programming like thus more comprehensible 
created_at: 2025-03-13T14:12:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -345,14 +341,14 @@ bool DescriptorClassGeneralBufferPass::Instrument() {
                 // Do here before we inject instructions into the block list below
                 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 (!RequiresInstrumentation(*function, *(inst_it->get()), true)) continue;
-                    Reset();
+                    if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, true)) continue;
path: layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
user: login: spencer-lunarg
body: it is just a dummy object
created_at: 2025-03-13T14:14:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -345,14 +341,14 @@ bool DescriptorClassGeneralBufferPass::Instrument() {
                 // Do here before we inject instructions into the block list below
                 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 (!RequiresInstrumentation(*function, *(inst_it->get()), true)) continue;
-                    Reset();
+                    if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, true)) continue;
+                    meta.Reset();
                 }
             }
 
             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 (!RequiresInstrumentation(*function, *(inst_it->get()), false)) continue;
+                if (!RequiresInstrumentation(*function, *(inst_it->get()), meta, false)) continue;
path: layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
user: login: spencer-lunarg
body: agree, save needing to build a reset and duplicating the variable
created_at: 2025-03-13T14:18:10Z
author_association: CONTRIBUTOR

PR comments:
user: login: ci-tester-lunarg
created_at: 2025-03-12T19:54:50Z
body: CI Vulkan-ValidationLayers build queued with queue ID 394005.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-12T19:55:02Z
body: CI Vulkan-ValidationLayers build # 19371 running.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-12T20:26:39Z
body: CI Vulkan-ValidationLayers build # 19371 passed.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-13T14:22:14Z
body: CI Vulkan-ValidationLayers build queued with queue ID 394569.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-13T14:25:02Z
body: CI Vulkan-ValidationLayers build # 19382 running.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-13T14:59:26Z
body: CI Vulkan-ValidationLayers build # 19382 passed.
author_association: COLLABORATOR