gpuav: Select pipeline to instrument post creation
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index 65b92e2..8c00152 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -211,6 +211,7 @@
     chassis/chassis_modification_state.h
     chassis/chassis_manual.cpp
     chassis/dispatch_object_manual.cpp
+    chassis/dispatch_object.h
     containers/range.h
     containers/range_map.h
     core_checks/cc_android.cpp
diff --git a/layers/VkLayer_khronos_validation.json.in b/layers/VkLayer_khronos_validation.json.in
index de5cebb..4f267c7 100644
--- a/layers/VkLayer_khronos_validation.json.in
+++ b/layers/VkLayer_khronos_validation.json.in
@@ -817,7 +817,7 @@
                                         {
                                             "key": "gpuav_select_instrumented_shaders",
                                             "label": "Enable instrumenting shaders selectively",
-                                            "description": "Select which shaders to instrument by passing a VkValidationFeaturesEXT struct with GPU-AV enabled in the VkShaderModuleCreateInfo pNext or using a regex matching a shader/pipeline debug name. Because this only validates the selected shaders, it will allow GPU-AV to run much faster.",
+                                            "description": "Select which shaders to instrument by passing a VkValidationFeaturesEXT struct with GPU-AV enabled in the VkShaderModuleCreateInfo pNext or using a regex matching a shader/pipeline debug name. Because this only validates the selected shaders/pipelines, it will allow GPU-AV to run much faster.",
                                             "url": "https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/main/docs/gpu_av_selective_shader.md",
                                             "type": "BOOL",
                                             "default": false,
diff --git a/layers/chassis/dispatch_object.h b/layers/chassis/dispatch_object.h
index f9bba74..26763db 100644
--- a/layers/chassis/dispatch_object.h
+++ b/layers/chassis/dispatch_object.h
@@ -231,7 +231,20 @@
         }
     }
 
+    // Replaces the "driver handle" in the "wrapped handle" to "driver handle" mapping.
+    // Returns the old "driver handle" if found.
+    template <typename HandleType>
+    HandleType Replace(HandleType wrapped_handle, HandleType new_driver_handle) {
+        const HandleType old_driver_handle = Find(wrapped_handle);
+        const uint64_t wrapped_handle_id = CastToUint64(wrapped_handle);
+        assert(wrapped_handle_id != 0);  // can't be 0, otherwise unwrap will apply special rule for VK_NULL_HANDLE
+        unique_id_mapping.insert_or_assign(wrapped_handle_id, CastToUint64(new_driver_handle));
+        return old_driver_handle;
+    }
+
     void UnwrapPnextChainHandles(const void* pNext);
+    void UnwrapComputePipelineCreateInfoHandles(vku::safe_VkComputePipelineCreateInfo& safe_ci);
+    void UnwrapGraphicsPipelineCreateInfoHandles(vku::safe_VkGraphicsPipelineCreateInfo& safe_ci);
 
     static std::atomic<uint64_t> global_unique_id;
     static vvl::concurrent_unordered_map<uint64_t, uint64_t, 4, HashedUint64> unique_id_mapping;
diff --git a/layers/chassis/dispatch_object_manual.cpp b/layers/chassis/dispatch_object_manual.cpp
index a038372..432608f 100644
--- a/layers/chassis/dispatch_object_manual.cpp
+++ b/layers/chassis/dispatch_object_manual.cpp
@@ -1095,6 +1095,61 @@
     }
 }
 
+void HandleWrapper::UnwrapGraphicsPipelineCreateInfoHandles(vku::safe_VkGraphicsPipelineCreateInfo& safe_ci) {
+    if (safe_ci.basePipelineHandle) {
+        safe_ci.basePipelineHandle = Unwrap(safe_ci.basePipelineHandle);
+    }
+    if (safe_ci.layout) {
+        safe_ci.layout = Unwrap(safe_ci.layout);
+    }
+
+    if (safe_ci.pStages) {
+        for (uint32_t idx1 = 0; idx1 < safe_ci.stageCount; ++idx1) {
+            UnwrapMappingInfo(this, safe_ci.pStages[idx1].pNext);
+
+            if (safe_ci.pStages[idx1].module) {
+                safe_ci.pStages[idx1].module = Unwrap(safe_ci.pStages[idx1].module);
+            }
+        }
+    }
+    if (safe_ci.renderPass) {
+        safe_ci.renderPass = Unwrap(safe_ci.renderPass);
+    }
+
+    auto* link_info = vku::FindStructInPNextChain<VkPipelineLibraryCreateInfoKHR>(safe_ci.pNext);
+    if (link_info) {
+        auto* unwrapped_libs = const_cast<VkPipeline*>(link_info->pLibraries);
+        for (uint32_t idx1 = 0; idx1 < link_info->libraryCount; ++idx1) {
+            unwrapped_libs[idx1] = Unwrap(link_info->pLibraries[idx1]);
+        }
+    }
+
+    auto device_generated_commands = vku::FindStructInPNextChain<VkGraphicsPipelineShaderGroupsCreateInfoNV>(safe_ci.pNext);
+    if (device_generated_commands) {
+        for (uint32_t idx1 = 0; idx1 < device_generated_commands->groupCount; ++idx1) {
+            for (uint32_t idx2 = 0; idx2 < device_generated_commands->pGroups[idx1].stageCount; ++idx2) {
+                auto unwrapped_stage =
+                    const_cast<VkPipelineShaderStageCreateInfo*>(&device_generated_commands->pGroups[idx1].pStages[idx2]);
+                if (device_generated_commands->pGroups[idx1].pStages[idx2].module) {
+                    unwrapped_stage->module = Unwrap(device_generated_commands->pGroups[idx1].pStages[idx2].module);
+                }
+            }
+        }
+        auto unwrapped_pipelines = const_cast<VkPipeline*>(device_generated_commands->pPipelines);
+        for (uint32_t idx1 = 0; idx1 < device_generated_commands->pipelineCount; ++idx1) {
+            unwrapped_pipelines[idx1] = Unwrap(device_generated_commands->pPipelines[idx1]);
+        }
+    }
+
+    auto* binary_info = vku::FindStructInPNextChain<VkPipelineBinaryInfoKHR>(safe_ci.pNext);
+    if (binary_info) {
+        auto* unwrapped_binaries = const_cast<VkPipelineBinaryKHR*>(binary_info->pPipelineBinaries);
+        for (uint32_t idx1 = 0; idx1 < binary_info->binaryCount; ++idx1) {
+            unwrapped_binaries[idx1] = Unwrap(binary_info->pPipelineBinaries[idx1]);
+        }
+    }
+}
+
 VkResult DispatchDevice::CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
                                                  const VkGraphicsPipelineCreateInfo* pCreateInfos,
                                                  const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) {
@@ -1118,7 +1173,6 @@
                         uses_depthstencil_attachment = true;
                 }
             }
-
             // We only want to find the case where the user is possibly building non-fragment output libraries
             bool has_fragment_output_state = true;
             if (auto lib_info = vku::FindStructInPNextChain<VkGraphicsPipelineLibraryCreateInfoEXT>(pCreateInfos[idx0].pNext)) {
@@ -1153,59 +1207,7 @@
                     original_color_attachment_formats;
             }
 
-            if (pCreateInfos[idx0].basePipelineHandle) {
-                local_pCreateInfos[idx0].basePipelineHandle = Unwrap(pCreateInfos[idx0].basePipelineHandle);
-            }
-            if (pCreateInfos[idx0].layout) {
-                local_pCreateInfos[idx0].layout = Unwrap(pCreateInfos[idx0].layout);
-            }
-
-            if (pCreateInfos[idx0].pStages) {
-                for (uint32_t idx1 = 0; idx1 < pCreateInfos[idx0].stageCount; ++idx1) {
-                    UnwrapMappingInfo(this, local_pCreateInfos[idx0].pStages[idx1].pNext);
-
-                    if (pCreateInfos[idx0].pStages[idx1].module) {
-                        local_pCreateInfos[idx0].pStages[idx1].module = Unwrap(pCreateInfos[idx0].pStages[idx1].module);
-                    }
-                }
-            }
-            if (pCreateInfos[idx0].renderPass) {
-                local_pCreateInfos[idx0].renderPass = Unwrap(pCreateInfos[idx0].renderPass);
-            }
-
-            auto* link_info = vku::FindStructInPNextChain<VkPipelineLibraryCreateInfoKHR>(local_pCreateInfos[idx0].pNext);
-            if (link_info) {
-                auto* unwrapped_libs = const_cast<VkPipeline*>(link_info->pLibraries);
-                for (uint32_t idx1 = 0; idx1 < link_info->libraryCount; ++idx1) {
-                    unwrapped_libs[idx1] = Unwrap(link_info->pLibraries[idx1]);
-                }
-            }
-
-            auto device_generated_commands =
-                vku::FindStructInPNextChain<VkGraphicsPipelineShaderGroupsCreateInfoNV>(local_pCreateInfos[idx0].pNext);
-            if (device_generated_commands) {
-                for (uint32_t idx1 = 0; idx1 < device_generated_commands->groupCount; ++idx1) {
-                    for (uint32_t idx2 = 0; idx2 < device_generated_commands->pGroups[idx1].stageCount; ++idx2) {
-                        auto unwrapped_stage =
-                            const_cast<VkPipelineShaderStageCreateInfo*>(&device_generated_commands->pGroups[idx1].pStages[idx2]);
-                        if (device_generated_commands->pGroups[idx1].pStages[idx2].module) {
-                            unwrapped_stage->module = Unwrap(device_generated_commands->pGroups[idx1].pStages[idx2].module);
-                        }
-                    }
-                }
-                auto unwrapped_pipelines = const_cast<VkPipeline*>(device_generated_commands->pPipelines);
-                for (uint32_t idx1 = 0; idx1 < device_generated_commands->pipelineCount; ++idx1) {
-                    unwrapped_pipelines[idx1] = Unwrap(device_generated_commands->pPipelines[idx1]);
-                }
-            }
-
-            auto* binary_info = vku::FindStructInPNextChain<VkPipelineBinaryInfoKHR>(local_pCreateInfos[idx0].pNext);
-            if (binary_info) {
-                auto* unwrapped_binaries = const_cast<VkPipelineBinaryKHR*>(binary_info->pPipelineBinaries);
-                for (uint32_t idx1 = 0; idx1 < binary_info->binaryCount; ++idx1) {
-                    unwrapped_binaries[idx1] = Unwrap(binary_info->pPipelineBinaries[idx1]);
-                }
-            }
+            UnwrapGraphicsPipelineCreateInfoHandles(local_pCreateInfos[idx0]);
         }
     }
     if (pipelineCache) {
@@ -2411,6 +2413,20 @@
     return device_dispatch_table.WriteResourceDescriptorsEXT(device, resourceCount, local_pResources[0].ptr(), pDescriptors);
 }
 
+void HandleWrapper::UnwrapComputePipelineCreateInfoHandles(vku::safe_VkComputePipelineCreateInfo& safe_ci) {
+    UnwrapPnextChainHandles(safe_ci.pNext);
+    if (safe_ci.stage.module) {
+        safe_ci.stage.module = Unwrap(safe_ci.stage.module);
+    }
+    UnwrapPnextChainHandles(safe_ci.stage.pNext);
+    if (safe_ci.layout) {
+        safe_ci.layout = Unwrap(safe_ci.layout);
+    }
+    if (safe_ci.basePipelineHandle) {
+        safe_ci.basePipelineHandle = Unwrap(safe_ci.basePipelineHandle);
+    }
+}
+
 VkResult DispatchDevice::CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
                                         const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator,
                                         VkPipeline* pPipelines) {
@@ -2424,17 +2440,7 @@
             local_pCreateInfos = new vku::safe_VkComputePipelineCreateInfo[createInfoCount];
             for (uint32_t index0 = 0; index0 < createInfoCount; ++index0) {
                 local_pCreateInfos[index0].initialize(&pCreateInfos[index0]);
-                UnwrapPnextChainHandles(local_pCreateInfos[index0].pNext);
-                if (pCreateInfos[index0].stage.module) {
-                    local_pCreateInfos[index0].stage.module = Unwrap(pCreateInfos[index0].stage.module);
-                }
-                UnwrapPnextChainHandles(local_pCreateInfos[index0].stage.pNext);
-                if (pCreateInfos[index0].layout) {
-                    local_pCreateInfos[index0].layout = Unwrap(pCreateInfos[index0].layout);
-                }
-                if (pCreateInfos[index0].basePipelineHandle) {
-                    local_pCreateInfos[index0].basePipelineHandle = Unwrap(pCreateInfos[index0].basePipelineHandle);
-                }
+                UnwrapComputePipelineCreateInfoHandles(local_pCreateInfos[index0]);
             }
         }
     }
diff --git a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp
index 242a1a6..8077321 100644
--- a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp
+++ b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp
@@ -19,6 +19,7 @@
 #include <vulkan/vulkan_core.h>
 #include <cstdint>
 
+#include "containers/container_utils.h"
 #include "error_message/error_location.h"
 #include "generated/vk_extension_helper.h"
 #include "generated/dispatch_functions.h"
@@ -405,6 +406,128 @@
     }
 }
 
+void GpuShaderInstrumentor::PreCallRecordSetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT* pNameInfo,
+                                                                    const RecordObject& record_obj) {
+    // Warning: This function is not thread safe WRT pipeline state accesses.
+    // It is assumed that in most cases, objects are named right after being created,
+    // and concurrent accesses should not be a worry.
+
+    if (!gpuav_settings.select_instrumented_shaders) {
+        return;
+    }
+
+    if (!gpuav_settings.IsSpirvModified()) {
+        return;
+    }
+    if (pNameInfo->objectType != VK_OBJECT_TYPE_PIPELINE || !pNameInfo->pObjectName) {
+        return;
+    }
+
+    if (!gpuav_settings.MatchesAnyShaderSelectionRegex(pNameInfo->pObjectName)) {
+        return;
+    }
+
+    if (disabled[handle_wrapping]) {
+        InternalError(LogObjectList(), record_obj.location,
+                      "For GPU-AV selective pipeline instrumentation post creation to work, handle wrapping needs to be enabled.");
+        return;
+    }
+
+    VkPipeline wrapped_pipeline = CastFromUint64<VkPipeline>(pNameInfo->objectHandle);
+    auto pipeline_state = Get<vvl::Pipeline>(wrapped_pipeline);
+    ASSERT_AND_RETURN(pipeline_state);
+
+    if (pipeline_state->instrumentation_data.was_instrumented) {
+        return;
+    }
+
+    if (!NeedPipelineCreationShaderInstrumentation(*pipeline_state, record_obj.location)) {
+        return;
+    }
+
+    auto layer_data = vvl::GetDispatchDevice(device);
+    ASSERT_AND_RETURN(layer_data);
+
+    // The pipeline was selected by name, not by individual shader name, so force all its shaders to be instrumented
+    for (const auto& stage_state : pipeline_state->stage_states) {
+        if (stage_state.module_state && stage_state.module_state->VkHandle() != VK_NULL_HANDLE) {
+            selected_instrumented_shaders.insert(stage_state.module_state->VkHandle());
+        }
+    }
+
+    VkPipeline instrumented_pipeline = VK_NULL_HANDLE;
+    // Can't instrument ray tracing pipeline post creation,
+    // As corresponding shader binding tables may have already been created.
+    if (pipeline_state->linking_shaders == 0 &&
+        IsValueIn(pipeline_state->pipeline_type, {VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE})) {
+        std::vector<chassis::ShaderInstrumentationMetadata> shader_instrumentation_metadata;
+        if (pipeline_state->pipeline_type == VK_PIPELINE_BIND_POINT_GRAPHICS) {
+            vku::safe_VkGraphicsPipelineCreateInfo new_pipeline_ci(pipeline_state->GraphicsCreateInfo());
+            new_pipeline_ci.flags &= ~VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
+            const bool success = PreCallRecordPipelineCreationShaderInstrumentation(
+                nullptr, *pipeline_state, new_pipeline_ci, uint32_t(pipeline_state->stage_states.size()), record_obj.location,
+                shader_instrumentation_metadata);
+            if (!success) {
+                InternalError(device, record_obj.location, "Failed to instrument graphics pipeline in SetDebugUtilsObjectNameEXT.");
+                return;
+            }
+
+            layer_data->UnwrapGraphicsPipelineCreateInfoHandles(new_pipeline_ci);
+            const VkResult result = layer_data->device_dispatch_table.CreateGraphicsPipelines(
+                device, VK_NULL_HANDLE, 1, new_pipeline_ci.ptr(), nullptr, &instrumented_pipeline);
+            if (result != VK_SUCCESS || instrumented_pipeline == VK_NULL_HANDLE) {
+                InternalError(device, record_obj.location,
+                              "Failed to create instrumented graphics pipeline in SetDebugUtilsObjectNameEXT.");
+                return;
+            }
+        } else if (pipeline_state->pipeline_type == VK_PIPELINE_BIND_POINT_COMPUTE) {
+            vku::safe_VkComputePipelineCreateInfo new_pipeline_ci(pipeline_state->ComputeCreateInfo());
+            new_pipeline_ci.flags &= ~VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
+            const bool success = PreCallRecordPipelineCreationShaderInstrumentation(
+                nullptr, *pipeline_state, new_pipeline_ci, uint32_t(pipeline_state->stage_states.size()), record_obj.location,
+                shader_instrumentation_metadata);
+            if (!success) {
+                InternalError(device, record_obj.location, "Failed to instrument compute pipeline in SetDebugUtilsObjectNameEXT.");
+                return;
+            }
+
+            layer_data->UnwrapComputePipelineCreateInfoHandles(new_pipeline_ci);
+            const VkResult result = layer_data->device_dispatch_table.CreateComputePipelines(
+                device, VK_NULL_HANDLE, 1, new_pipeline_ci.ptr(), nullptr, &instrumented_pipeline);
+            if (result != VK_SUCCESS || instrumented_pipeline == VK_NULL_HANDLE) {
+                InternalError(device, record_obj.location,
+                              "Failed to create instrumented compute pipeline in SetDebugUtilsObjectNameEXT.");
+                return;
+            }
+        }
+
+        PostCallRecordPipelineCreationShaderInstrumentation(*pipeline_state, uint32_t(pipeline_state->stage_states.size()),
+                                                            shader_instrumentation_metadata);
+    } else {
+        vku::safe_VkGraphicsPipelineCreateInfo new_pipeline_ci(pipeline_state->GraphicsCreateInfo());
+        const bool success =
+            PreCallRecordPipelineCreationShaderInstrumentationGPL(nullptr, *pipeline_state, new_pipeline_ci, record_obj.location);
+        if (!success) {
+            InternalError(device, record_obj.location,
+                          "Failed to instrument graphics pipeline library in SetDebugUtilsObjectNameEXT.");
+            return;
+        }
+
+        layer_data->UnwrapGraphicsPipelineCreateInfoHandles(new_pipeline_ci);
+        const VkResult result = layer_data->device_dispatch_table.CreateGraphicsPipelines(
+            device, VK_NULL_HANDLE, 1, new_pipeline_ci.ptr(), nullptr, &instrumented_pipeline);
+        if (result != VK_SUCCESS || instrumented_pipeline == VK_NULL_HANDLE) {
+            InternalError(device, record_obj.location,
+                          "Failed to create instrumented graphics pipeline in SetDebugUtilsObjectNameEXT.");
+            return;
+        }
+    }
+
+    const VkPipeline old_pipeline = layer_data->Replace(pipeline_state->VkHandle(), instrumented_pipeline);
+    gpuav::PipelineSubState& pipeline_sub_state = SubState(*pipeline_state);
+    pipeline_sub_state.AddHandleToDestroy(old_pipeline);
+}
+
 void GpuShaderInstrumentor::PostCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo,
                                                              const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule,
                                                              const RecordObject& record_obj,
@@ -1117,7 +1240,8 @@
     }
 }
 
-bool GpuShaderInstrumentor::IsPipelineSelectedForInstrumentation(VkPipeline pipeline, const Location& loc) {
+bool GpuShaderInstrumentor::IsPipelineSelectedForInstrumentation(const void* pipeline_ci_pnext, VkPipeline pipeline,
+                                                                 const Location& loc) {
     if (!gpuav_settings.select_instrumented_shaders) {
         return true;
     }
@@ -1125,12 +1249,17 @@
     bool should_instrument_pipeline = false;
     {
         std::string pipeline_debug_name;
-        {
+        if (auto debug = vku::FindStructInPNextChain<VkDebugUtilsObjectNameInfoEXT>(pipeline_ci_pnext)) {
+            if (debug->pObjectName) {
+                pipeline_debug_name = debug->pObjectName;
+            }
+        } else if (pipeline != VK_NULL_HANDLE) {
             std::unique_lock<std::mutex> lock(debug_report->debug_output_mutex);
             pipeline_debug_name = debug_report->GetUtilsObjectNameNoLock(HandleToUint64(pipeline));
         }
-
-        should_instrument_pipeline = gpuav_settings.MatchesAnyShaderSelectionRegex(pipeline_debug_name);
+        if (!pipeline_debug_name.empty()) {
+            should_instrument_pipeline = gpuav_settings.MatchesAnyShaderSelectionRegex(pipeline_debug_name);
+        }
     }
     if (should_instrument_pipeline) {
         LogInfo("GPU-AV::Selective shader instrumentation", LogObjectList(), loc, "(%s) will be instrumented for validation.",
@@ -1237,6 +1366,9 @@
     // Can set this once for all shaders in the pipeline
     BuildDescriptorSetLayoutInfo(pipeline_state, interface.instrumentation_dsl);
 
+    bool is_pipeline_selected_for_instrumentation =
+        IsPipelineSelectedForInstrumentation(modified_pipeline_ci.pNext, VK_NULL_HANDLE, loc);
+
     for (uint32_t stage_state_i = 0; stage_state_i < stages_count; ++stage_state_i) {
         const auto& stage_state = pipeline_state.stage_states[stage_state_i];
         auto modified_module_state = std::const_pointer_cast<vvl::ShaderModule>(stage_state.module_state);
@@ -1259,8 +1391,9 @@
                 const_cast<vku::safe_VkShaderModuleCreateInfo*>(reinterpret_cast<const vku::safe_VkShaderModuleCreateInfo*>(
                     vku::FindStructInPNextChain<VkShaderModuleCreateInfo>(stage_ci.pNext)));
 
-            if (!IsShaderSelectedForInstrumentation(modified_shader_module_ci, modified_module_state->VkHandle(),
-                                                    loc.dot(vvl::Field::pStages, stage_state_i).dot(vvl::Field::module))) {
+            if (!(is_pipeline_selected_for_instrumentation ||
+                  IsShaderSelectedForInstrumentation(modified_shader_module_ci, modified_module_state->VkHandle(),
+                                                     loc.dot(vvl::Field::pStages, stage_state_i).dot(vvl::Field::module)))) {
                 continue;
             }
         }
@@ -1416,10 +1549,15 @@
         // creation process no matter caching state.
         new_lib_ci.flags &= ~VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
         bool is_library_instrumented = false;
-
         // If pipeline library is selected for instrumentation, force instrumentation of all its shaders
-        const bool force_pipeline_instrumentation =
-            IsPipelineSelectedForInstrumentation(modified_lib->VkHandle(), loc.dot(vvl::Field::pLibraries, modified_lib_i));
+        bool is_pipeline_selected_for_instrumentation = IsPipelineSelectedForInstrumentation(
+            modified_pipeline_ci.pNext, modified_lib->VkHandle(), loc.dot(vvl::Field::pLibraries, modified_lib_i));
+        // Case where pipeline is instrumented post creation. Otherwise, pipeline handle has yet to be created!
+        // currently only useful when this function is called in PreCallRecordSetDebugUtilsObjectNameEXT
+        if (linked_pipeline_state.VkHandle() != VK_NULL_HANDLE) {
+            is_pipeline_selected_for_instrumentation |=
+                IsPipelineSelectedForInstrumentation(modified_pipeline_ci.pNext, linked_pipeline_state.VkHandle(), loc);
+        }
 
         for (uint32_t stage_state_i = 0; stage_state_i < static_cast<uint32_t>(modified_lib->stage_states.size());
              ++stage_state_i) {
@@ -1457,9 +1595,9 @@
                         vku::FindStructInPNextChain<VkShaderModuleCreateInfo>(modified_stage_ci->pNext)));
 
                 // TODO - this is in need of testing, when only selecting various library as well as selecting everything
-                if (!force_pipeline_instrumentation &&
-                    !IsShaderSelectedForInstrumentation(modified_shader_module_ci, modified_module_state->VkHandle(),
-                                                        loc.dot(vvl::Field::pStages, stage_state_i).dot(vvl::Field::module))) {
+                if (!(is_pipeline_selected_for_instrumentation ||
+                      IsShaderSelectedForInstrumentation(modified_shader_module_ci, modified_module_state->VkHandle(),
+                                                         loc.dot(vvl::Field::pStages, stage_state_i).dot(vvl::Field::module)))) {
                     continue;
                 }
 
diff --git a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.h b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.h
index 3949760..5720a76 100644
--- a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.h
+++ b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.h
@@ -103,6 +103,9 @@
                                            const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
                                            const RecordObject &record_obj, chassis::CreatePipelineLayout &chassis_state) override;
 
+    void PreCallRecordSetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT* pNameInfo,
+                                                 const RecordObject& record_obj) override;
+
     void PostCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
                                           const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule,
                                           const RecordObject &record_obj, chassis::CreateShaderModule &chassis_state) override;
@@ -246,7 +249,7 @@
     bool set_null_descriptors_ = false;
 
   private:
-    bool IsPipelineSelectedForInstrumentation(VkPipeline pipeline, const Location &loc);
+    bool IsPipelineSelectedForInstrumentation(const void* pipeline_ci_pnext, VkPipeline pipeline, const Location& loc);
     bool IsShaderSelectedForInstrumentation(vku::safe_VkShaderModuleCreateInfo *modified_shader_module_ci,
                                             VkShaderModule modified_shader, const Location &loc);
     void AddDescriptorHeapMappings(VkBaseOutStructure *create_info);
diff --git a/layers/gpuav/resources/gpuav_state_trackers.cpp b/layers/gpuav/resources/gpuav_state_trackers.cpp
index 2742c2e..0a2fe8f 100644
--- a/layers/gpuav/resources/gpuav_state_trackers.cpp
+++ b/layers/gpuav/resources/gpuav_state_trackers.cpp
@@ -671,9 +671,9 @@
 PipelineSubState::PipelineSubState(Validator& gpuav, vvl::Pipeline& pipeline) : vvl::PipelineSubState(pipeline), gpuav_(gpuav) {}
 
 VkPipelineLayout PipelineSubState::GetPipelineLayoutUnion(const Location& loc, vvl::DescriptorMode mode) const {
-    std::unique_lock<std::mutex> recreated_layout_lock(recreated_layout_mutex);
-    if (recreated_layout != VK_NULL_HANDLE) {
-        return recreated_layout;
+    std::unique_lock<std::mutex> recreated_layout_lock(mutex_);
+    if (recreated_layout_ != VK_NULL_HANDLE) {
+        return recreated_layout_;
     }
 
     const std::shared_ptr<const vvl::PipelineLayout> pipeline_layout_state = base.PipelineLayoutState();
@@ -719,7 +719,7 @@
         pipeline_layout_ci.pPushConstantRanges = pipeline_layout_state->push_constant_ranges_layout->data();
     }
 
-    const VkResult result = DispatchCreatePipelineLayout(gpuav_.device, &pipeline_layout_ci, nullptr, &recreated_layout);
+    const VkResult result = DispatchCreatePipelineLayout(gpuav_.device, &pipeline_layout_ci, nullptr, &recreated_layout_);
     (void)result;
     assert(result == VK_SUCCESS);
 
@@ -727,15 +727,27 @@
         DispatchDestroyDescriptorSetLayout(gpuav_.device, set_layout_handles[i], nullptr);
     }
 
-    return recreated_layout;
+    return recreated_layout_;
 }
 
 void PipelineSubState::Destroy() {
-    std::unique_lock<std::mutex> recreated_layout_lock(recreated_layout_mutex);
-    if (recreated_layout != VK_NULL_HANDLE) {
-        DispatchDestroyPipelineLayout(gpuav_.device, recreated_layout, nullptr);
-        recreated_layout = VK_NULL_HANDLE;
+    std::unique_lock<std::mutex> recreated_layout_lock(mutex_);
+    if (recreated_layout_ != VK_NULL_HANDLE) {
+        DispatchDestroyPipelineLayout(gpuav_.device, recreated_layout_, nullptr);
+        recreated_layout_ = VK_NULL_HANDLE;
     }
+    if (uninstrumented_pipeline != VK_NULL_HANDLE) {
+        // vkDestroyPipeline expects an unwrapped handle,
+        // so cannot use DispatchDestroyPipeline as it will try to unwrap supplied pipeline handle
+        auto layer_data = vvl::GetDispatchDevice(gpuav_.device);
+        layer_data->device_dispatch_table.DestroyPipeline(gpuav_.device, uninstrumented_pipeline, nullptr);
+    }
+}
+
+void PipelineSubState::AddHandleToDestroy(VkPipeline pipeline) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    assert(uninstrumented_pipeline == VK_NULL_HANDLE);
+    uninstrumented_pipeline = pipeline;
 }
 
 }  // namespace gpuav
diff --git a/layers/gpuav/resources/gpuav_state_trackers.h b/layers/gpuav/resources/gpuav_state_trackers.h
index 82d3e49..7bdd158 100644
--- a/layers/gpuav/resources/gpuav_state_trackers.h
+++ b/layers/gpuav/resources/gpuav_state_trackers.h
@@ -397,15 +397,19 @@
     explicit PipelineSubState(Validator &gpuav, vvl::Pipeline &pipeline);
 
     void Destroy() override;
-
+    // Specifically for pipeline instrumented post original creation:
+    // The old pipeline could be in use at time of instrumentation,
+    // so defer old pipeline destroy to Destroy() call.
+    void AddHandleToDestroy(VkPipeline pipeline);
     VkPipelineLayout GetPipelineLayoutUnion(const Location &loc, vvl::DescriptorMode mode) const;
 
   private:
     // Multiple threads can record multiple commands using the same pipeline,
-    // so pipeline layout recreation has to be thread safe
-    mutable std::mutex recreated_layout_mutex{};
-    mutable VkPipelineLayout recreated_layout = VK_NULL_HANDLE;
+    // so layout recreation and deferred pipeline destruction have to be thread safe
+    mutable std::mutex mutex_{};
+    mutable VkPipelineLayout recreated_layout_ = VK_NULL_HANDLE;
     Validator &gpuav_;
+    VkPipeline uninstrumented_pipeline = VK_NULL_HANDLE;
 };
 
 static inline PipelineSubState &SubState(vvl::Pipeline &pipeline) {
diff --git a/layers/layer_options.cpp b/layers/layer_options.cpp
index 6644d82..0790149 100644
--- a/layers/layer_options.cpp
+++ b/layers/layer_options.cpp
@@ -1360,6 +1360,17 @@
         }
     }
 
+    // Only truly needed for pipelines (see GpuShaderInstrumentor::PreCallRecordSetDebugUtilsObjectNameEXT)
+    // In the future, could be removed in favor of debug names supplied at pipeline creation time.
+    if (gpuav_settings.select_instrumented_shaders) {
+        if (settings_data->disabled[handle_wrapping]) {
+            setting_warnings.emplace_back(
+                "Handle wrapping has been disabled, but GPU-AV selective shader instrumentation is enabled. Forcing activation of "
+                "handle wrapping.");
+            settings_data->disabled[handle_wrapping] = false;
+        }
+    }
+
     // After checking the various ways to enable both DebugPrintf and GPU-AV, disable non-DebugPrintf portion if not used
     if (settings_data->enabled[debug_printf_validation] && !settings_data->enabled[gpu_validation]) {
         gpuav_settings.SetOnlyDebugPrintf();
diff --git a/layers/vk_layer_settings.txt b/layers/vk_layer_settings.txt
index c3870bd..fef56bf 100644
--- a/layers/vk_layer_settings.txt
+++ b/layers/vk_layer_settings.txt
@@ -167,7 +167,7 @@
 
 # Enable instrumenting shaders selectively
 # =====================
-# Select which shaders to instrument by passing a VkValidationFeaturesEXT struct with GPU-AV enabled in the VkShaderModuleCreateInfo pNext or using a regex matching a shader/pipeline debug name. Because this only validates the selected shaders, it will allow GPU-AV to run much faster.
+# Select which shaders to instrument by passing a VkValidationFeaturesEXT struct with GPU-AV enabled in the VkShaderModuleCreateInfo pNext or using a regex matching a shader/pipeline debug name. Because this only validates the selected shaders/pipelines, it will allow GPU-AV to run much faster.
 khronos_validation.gpuav_select_instrumented_shaders = false
 
 # Shader instrumentation
diff --git a/tests/unit/gpu_av.cpp b/tests/unit/gpu_av.cpp
index f7165c5..095dae3 100644
--- a/tests/unit/gpu_av.cpp
+++ b/tests/unit/gpu_av.cpp
@@ -126,7 +126,7 @@
                          shader_regexes.data()};
 
     RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
-    InitState();
+    RETURN_IF_SKIP(InitState());
     InitRenderTarget();
 
     vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
@@ -181,6 +181,227 @@
     m_errorMonitor->VerifyFound();
 }
 
+TEST_F(NegativeGpuAV, SelectInstrumentedComputePipelineRegex) {
+    TEST_DESCRIPTION("Selectively instrument a compute pipeline for validation, using regexes");
+    SetTargetApiVersion(VK_API_VERSION_1_2);
+    AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+    std::vector<VkLayerSettingEXT> layer_settings(2);
+    layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
+    std::array<const char*, 1> shader_regexes = {{"pipeline_foo"}};
+    layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
+                         shader_regexes.data()};
+
+    RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
+    RETURN_IF_SKIP(InitState());
+
+    vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
+    OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
+
+    const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
+    descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+    descriptor_set.UpdateDescriptorSets();
+
+    const char cs_source[] = R"glsl(
+        #version 450
+        layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
+        void main() {
+                Data.data[4] = 0xdeadca71;
+        }
+    )glsl";
+
+    CreateComputePipelineHelper pipe(*this);
+    pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr, "main");
+    pipe.cp_ci_.layout = pipeline_layout;
+    pipe.CreateComputePipeline();
+
+    VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
+    name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
+    name_info.pObjectName = "pipeline_foo";
+    name_info.objectHandle = uint64_t(pipe.Handle());
+    vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
+
+    m_command_buffer.Begin();
+    vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
+                              nullptr);
+    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
+    vk::CmdDispatch(m_command_buffer, 1, 1, 1);
+    m_command_buffer.End();
+
+    m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDispatch-storageBuffers-06936", "pipeline_foo");
+    m_default_queue->SubmitAndWait(m_command_buffer);
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(NegativeGpuAV, SelectInstrumentedPipelineLibrariesRegex) {
+    TEST_DESCRIPTION(
+        "Use one library to link two pipelines. Destroy first one before creating second one. Second one should be instrumented.");
+    AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
+    AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary);
+    AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
+    AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+    std::vector<VkLayerSettingEXT> layer_settings(2);
+    layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
+    std::array<const char*, 1> shader_regexes = {{"pipeline_foo"}};
+    layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
+                         shader_regexes.data()};
+
+    RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
+    RETURN_IF_SKIP(InitState());
+    InitRenderTarget();
+
+    vkt::Buffer offset_buffer(*m_device, 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
+    vkt::Buffer write_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
+
+    OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
+                                                  {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
+    const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
+    descriptor_set.WriteDescriptorBufferInfo(0, offset_buffer, 0, VK_WHOLE_SIZE);
+    descriptor_set.WriteDescriptorBufferInfo(1, write_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+    descriptor_set.UpdateDescriptorSets();
+
+    uint32_t* data = (uint32_t*)offset_buffer.Memory().Map();
+    *data = 8;
+
+    const char vertshader[] = R"glsl(
+        #version 450
+        layout(set = 0, binding = 0) uniform Foo { uint index[]; };
+        layout(set = 0, binding = 1) buffer StorageBuffer { uint data[]; };
+        void main() {
+            uint index = index[0];
+            data[index] = 0xdeadca71;
+        }
+    )glsl";
+
+    // Create VkShaderModule to pass in
+    VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT);
+    VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
+
+    CreatePipelineHelper vertex_input_lib(*this);
+    vertex_input_lib.InitVertexInputLibInfo();
+    vertex_input_lib.CreateGraphicsPipeline(false);
+
+    // For GPU-AV tests this shrinks things so only a single fragment is executed
+    VkViewport viewport = {0, 0, 1, 1, 0, 1};
+    VkRect2D scissor = {{0, 0}, {1, 1}};
+
+    CreatePipelineHelper pre_raster_lib(*this);
+    {
+        pre_raster_lib.InitPreRasterLibInfo(&vs.GetStageCreateInfo());
+        pre_raster_lib.vp_state_ci_.pViewports = &viewport;
+        pre_raster_lib.vp_state_ci_.pScissors = &scissor;
+        pre_raster_lib.gp_ci_.layout = pipeline_layout;
+        pre_raster_lib.CreateGraphicsPipeline();
+    }
+
+    CreatePipelineHelper frag_shader_lib(*this);
+    {
+        frag_shader_lib.InitFragmentLibInfo(&fs.GetStageCreateInfo());
+        frag_shader_lib.gp_ci_.layout = pipeline_layout;
+        frag_shader_lib.CreateGraphicsPipeline(false);
+    }
+
+    CreatePipelineHelper frag_out_lib(*this);
+    frag_out_lib.InitFragmentOutputLibInfo();
+    frag_out_lib.CreateGraphicsPipeline(false);
+
+    VkPipeline libraries[4] = {
+        vertex_input_lib,
+        pre_raster_lib,
+        frag_shader_lib,
+        frag_out_lib,
+    };
+    VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper();
+    link_info.libraryCount = size32(libraries);
+    link_info.pLibraries = libraries;
+
+    VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info);
+    exe_pipe_ci.layout = pipeline_layout;
+    {
+        vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci);
+    }
+    vkt::Pipeline exe_pipe_2(*m_device, exe_pipe_ci);
+
+    VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
+    name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
+    name_info.pObjectName = "pipeline_foo";
+    name_info.objectHandle = uint64_t(exe_pipe_2.handle());
+    vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
+
+    m_command_buffer.Begin();
+    m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
+    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe_2);
+    vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
+                              nullptr);
+    vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
+    m_command_buffer.EndRenderPass();
+    m_command_buffer.End();
+
+    m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDraw-storageBuffers-06936", "pipeline_foo", 3);
+
+    m_default_queue->SubmitAndWait(m_command_buffer);
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(NegativeGpuAV, SelectInstrumentedGraphicsPipelineRegex) {
+    TEST_DESCRIPTION("Selectively instrument a pipeline for validation, using regexes");
+    SetTargetApiVersion(VK_API_VERSION_1_2);
+    AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+    AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
+    std::vector<VkLayerSettingEXT> layer_settings(2);
+    layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
+    std::array<const char*, 1> shader_regexes = {{"pipeline_foo"}};
+    layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
+                         shader_regexes.data()};
+
+    RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
+    RETURN_IF_SKIP(InitState());
+    InitRenderTarget();
+
+    vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
+    OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
+
+    const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
+    descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+    descriptor_set.UpdateDescriptorSets();
+    const char vertshader[] = R"glsl(
+        #version 450
+        layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
+        void main() {
+                Data.data[4] = 0xdeadca71;
+        }
+        )glsl";
+
+    VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr, "main");
+    VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr,
+                   "main");
+
+    CreatePipelineHelper pipe(*this);
+    pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
+
+    pipe.gp_ci_.layout = pipeline_layout;
+    pipe.CreateGraphicsPipeline();
+
+    VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
+    name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
+
+    name_info.pObjectName = "pipeline_foo";
+    name_info.objectHandle = uint64_t(pipe.Handle());
+    vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
+
+    m_command_buffer.Begin();
+    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
+    m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
+    vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
+                              nullptr);
+    vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
+    m_command_buffer.EndRenderPass();
+    m_command_buffer.End();
+
+    m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDraw-storageBuffers-06936", "pipeline_foo", 3);
+    m_default_queue->SubmitAndWait(m_command_buffer);
+    m_errorMonitor->VerifyFound();
+}
+
 TEST_F(NegativeGpuAV, SelectInstrumentedShadersRegexDestroyedShaders) {
     TEST_DESCRIPTION(
         "Selectively instrument shaders for validation, using regexes: all shaders matching regexes must be instrumented. Here it "
@@ -195,7 +416,7 @@
                          shader_regexes.data()};
 
     RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
-    InitState();
+    RETURN_IF_SKIP(InitState());
     InitRenderTarget();
 
     vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);