gpuav: Select shader to instrument post creation
diff --git a/layers/chassis/chassis_modification_state.h b/layers/chassis/chassis_modification_state.h index 2a62d5f..a1fc0ed 100644 --- a/layers/chassis/chassis_modification_state.h +++ b/layers/chassis/chassis_modification_state.h
@@ -68,6 +68,7 @@ // When using GPU-AV the pCreateInfo is modified on the user bool is_modified = false; + bool force_shader_instrumentation = false; std::vector<vku::safe_VkShaderCreateInfoEXT> modified_create_infos; const VkShaderCreateInfoEXT* pCreateInfos = nullptr;
diff --git a/layers/chassis/dispatch_object.h b/layers/chassis/dispatch_object.h index 95ec081..27688cb 100644 --- a/layers/chassis/dispatch_object.h +++ b/layers/chassis/dispatch_object.h
@@ -254,6 +254,7 @@ void UnwrapPnextChainHandles(const void* pNext); void UnwrapComputePipelineCreateInfoHandles(vku::safe_VkComputePipelineCreateInfo& safe_ci); void UnwrapGraphicsPipelineCreateInfoHandles(vku::safe_VkGraphicsPipelineCreateInfo& safe_ci); + void UnwrapShaderObjectCreateInfoHandles(vku::safe_VkShaderCreateInfoEXT& 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 7c6a408..441a561 100644 --- a/layers/chassis/dispatch_object_manual.cpp +++ b/layers/chassis/dispatch_object_manual.cpp
@@ -2803,9 +2803,20 @@ return result; } +void HandleWrapper::UnwrapShaderObjectCreateInfoHandles(vku::safe_VkShaderCreateInfoEXT& safe_ci) { + UnwrapMappingInfo(this, safe_ci.pNext); + + if (safe_ci.pSetLayouts) { + for (uint32_t index1 = 0; index1 < safe_ci.setLayoutCount; ++index1) { + safe_ci.pSetLayouts[index1] = Unwrap(safe_ci.pSetLayouts[index1]); + } + } +} + VkResult DispatchDevice::CreateShadersEXT(VkDevice device, uint32_t createInfoCount, const VkShaderCreateInfoEXT* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkShaderEXT* pShaders) { if (!wrap_handles) return device_dispatch_table.CreateShadersEXT(device, createInfoCount, pCreateInfos, pAllocator, pShaders); + small_vector<vku::safe_VkShaderCreateInfoEXT, DISPATCH_MAX_STACK_ALLOCATIONS> var_local_pCreateInfos; vku::safe_VkShaderCreateInfoEXT* local_pCreateInfos = nullptr; if (pCreateInfos) { @@ -2814,14 +2825,7 @@ for (uint32_t index0 = 0; index0 < createInfoCount; ++index0) { local_pCreateInfos[index0].initialize(&pCreateInfos[index0]); - - UnwrapMappingInfo(this, local_pCreateInfos[index0].pNext); - - if (local_pCreateInfos[index0].pSetLayouts) { - for (uint32_t index1 = 0; index1 < local_pCreateInfos[index0].setLayoutCount; ++index1) { - local_pCreateInfos[index0].pSetLayouts[index1] = Unwrap(local_pCreateInfos[index0].pSetLayouts[index1]); - } - } + UnwrapShaderObjectCreateInfoHandles(local_pCreateInfos[index0]); } }
diff --git a/layers/gpuav/core/gpuav_setup.cpp b/layers/gpuav/core/gpuav_setup.cpp index 1474042..b3741f7 100644 --- a/layers/gpuav/core/gpuav_setup.cpp +++ b/layers/gpuav/core/gpuav_setup.cpp
@@ -82,7 +82,9 @@ DescriptorIdPool& desc_id_pool = shared_resources_cache.Get<DescriptorIdPool>(); obj.SetSubState(container_type, std::make_unique<TensorViewSubState>(obj, desc_id_pool)); } -void Validator::Created(vvl::ShaderObject& obj) { obj.SetSubState(container_type, std::make_unique<ShaderObjectSubState>(obj)); } +void Validator::Created(vvl::ShaderObject& obj) { + obj.SetSubState(container_type, std::make_unique<ShaderObjectSubState>(*this, obj)); +} void Validator::Created(vvl::Pipeline& obj) { obj.SetSubState(container_type, std::make_unique<PipelineSubState>(*this, obj)); }
diff --git a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp index b67d0e7..a9d2f1e 100644 --- a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp +++ b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp
@@ -414,7 +414,7 @@ if (!gpuav_settings.IsSpirvModified()) { return; } - if (pNameInfo->objectType != VK_OBJECT_TYPE_PIPELINE || !pNameInfo->pObjectName) { + if (!pNameInfo->pObjectName) { return; } @@ -428,43 +428,87 @@ return; } - VkPipeline wrapped_pipeline = CastFromUint64<VkPipeline>(pNameInfo->objectHandle); - auto pipeline_state = Get<vvl::Pipeline>(wrapped_pipeline); - ASSERT_AND_RETURN(pipeline_state); - PipelineSubState& pipeline_sub_state = SubState(*pipeline_state); + if (pNameInfo->objectType == VK_OBJECT_TYPE_PIPELINE) { + VkPipeline wrapped_pipeline = CastFromUint64<VkPipeline>(pNameInfo->objectHandle); + auto pipeline_state = Get<vvl::Pipeline>(wrapped_pipeline); + ASSERT_AND_RETURN(pipeline_state); + PipelineSubState& pipeline_sub_state = SubState(*pipeline_state); - if (pipeline_sub_state.status.host.is_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()); + if (pipeline_sub_state.status.host.is_instrumented) { + return; } - } - 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) { + 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()); - 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); + 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 in SetDebugUtilsObjectNameEXT."); + InternalError(device, record_obj.location, + "Failed to instrument graphics pipeline library in SetDebugUtilsObjectNameEXT."); return; } @@ -476,51 +520,52 @@ "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); + pipeline_sub_state.AddHandleToDestroy(old_pipeline); } - const VkPipeline old_pipeline = layer_data->Replace(pipeline_state->VkHandle(), instrumented_pipeline); - pipeline_sub_state.AddHandleToDestroy(old_pipeline); + if (pNameInfo->objectType == VK_OBJECT_TYPE_SHADER_EXT) { + VkShaderEXT wrapped_shader = CastFromUint64<VkShaderEXT>(pNameInfo->objectHandle); + auto shader_state = Get<vvl::ShaderObject>(wrapped_shader); + ASSERT_AND_RETURN(shader_state); + ShaderObjectSubState& shader_sub_state = SubState(*shader_state); + if (shader_sub_state.instrumented_status.host.is_instrumented) { + return; + } + + if (!shader_sub_state.original_module) { + return; + } + + vku::safe_VkShaderCreateInfoEXT new_shader_ci(shader_sub_state.original_create_info); + new_shader_ci.codeSize = shader_sub_state.original_module->words_.size() * sizeof(uint32_t); + new_shader_ci.pCode = shader_sub_state.original_module->words_.data(); + chassis::ShaderObject chassis_state(1, new_shader_ci.ptr()); + + VkShaderEXT instrumented_shader = VK_NULL_HANDLE; + chassis_state.force_shader_instrumentation = true; + PreCallRecordCreateShadersEXT(device, 1, new_shader_ci.ptr(), nullptr, &wrapped_shader, record_obj, chassis_state); + + new_shader_ci = chassis_state.modified_create_infos[0]; + + auto layer_data = vvl::GetDispatchDevice(device); + ASSERT_AND_RETURN(layer_data); + + layer_data->UnwrapShaderObjectCreateInfoHandles(new_shader_ci); + const VkResult result = + layer_data->device_dispatch_table.CreateShadersEXT(device, 1, new_shader_ci.ptr(), nullptr, &instrumented_shader); + if (result != VK_SUCCESS || instrumented_shader == VK_NULL_HANDLE) { + InternalError(device, record_obj.location, "Failed to create instrumented VkShaderEXT in SetDebugUtilsObjectNameEXT."); + return; + } + + const VkShaderEXT old_shader = layer_data->Replace(wrapped_shader, instrumented_shader); + shader_sub_state.AddHandleToDestroy(old_shader); + + PostCallRecordCreateShadersEXT(device, 1, new_shader_ci.ptr(), nullptr, &wrapped_shader, record_obj, chassis_state); + } } void GpuShaderInstrumentor::PostCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, @@ -640,7 +685,7 @@ "solution is use the SPIR-V if you want to use debugging tools."); } continue; - } else if (!chassis_state.module_states[i]) { + } else if (!chassis_state.force_shader_instrumentation && !chassis_state.module_states[i]) { continue; } @@ -663,7 +708,12 @@ "for VkShaderEXT created with it, therefore no validation error will be repored for them by GPU-AV at " "runtime."; InternalWarning(device, record_obj.location, strm.str().c_str()); - } else if (gpuav_settings.select_instrumented_shaders && !IsSelectiveInstrumentationEnabled(new_create_info.pNext)) { + } + // Because shader objects can be instrumented post creation at object labeling time, + // a mechanism is needed to bypass selective shader instrumentation at this level. + // In this case, the decision to instrument or not is done at RecordSetDebugUtilsObjectNameEXT time. + else if (!chassis_state.force_shader_instrumentation && gpuav_settings.select_instrumented_shaders && + !IsSelectiveInstrumentationEnabled(new_create_info.pNext)) { continue; } else { // Modify the pipeline layout by: @@ -715,10 +765,12 @@ if (!gpuav_settings.IsSpirvModified()) { return; } - // This can occur if the driver failed to compile the instrumented shader or if a PreCall step failed - if (!chassis_state.is_modified) { + + if (!gpuav_settings.select_instrumented_shaders && !chassis_state.is_modified) { + // This can occur if the driver failed to compile the instrumented shader or if a PreCall step failed return; } + for (uint32_t i = 0; i < createInfoCount; ++i) { // If there are multiple shaders being created, and one is bad, will return a non VK_SUCCESS but we need to check if the // VkShaderEXT was null or not to actually know if it was created @@ -726,22 +778,35 @@ if (shader_handle == VK_NULL_HANDLE) { continue; } + const auto& shader_object_state = Get<vvl::ShaderObject>(shader_handle); + ASSERT_AND_CONTINUE(shader_object_state); + auto& sub_state = SubState(*shader_object_state); auto& instrumentation_data = chassis_state.instrumentations_data[i]; + // If select_instrumented_shaders is enabled, GPU-AV might need + // SPIR-V code at object labeling time to instrument. + // Save state needed to do that. + if (gpuav_settings.select_instrumented_shaders && !instrumentation_data.status.host.is_instrumented && + pCreateInfos[i].codeType == VK_SHADER_CODE_TYPE_SPIRV_EXT) { + sub_state.original_create_info.initialize(&pCreateInfos[i]); + sub_state.original_module = chassis_state.module_states[i]; + } + + if (!chassis_state.is_modified) { + continue; + } + // if the shader for some reason was not instrumented, there is nothing to save // (like not using VK_SHADER_CODE_TYPE_SPIRV_EXT) if (!instrumentation_data.status.host.is_instrumented) { continue; } - const auto& shader_object_state = Get<vvl::ShaderObject>(shader_handle); - ASSERT_AND_CONTINUE(shader_object_state); - auto& sub_state = SubState(*shader_object_state); + sub_state.original_create_info.initialize(&pCreateInfos[i]); sub_state.instrumented_status.Append(instrumentation_data.status); sub_state.unique_shader_id = instrumentation_data.unique_shader_id; - // Note - this doesn't make a deep copy of the pCode, but does of the DescriptorSetLayout which we - sub_state.original_create_info.initialize(&pCreateInfos[i]); + // No pCode deep copy // We currently need to store a copy of the original, non-instrumented shader so if there is debug information. std::vector<uint32_t> code;
diff --git a/layers/gpuav/resources/gpuav_state_trackers.cpp b/layers/gpuav/resources/gpuav_state_trackers.cpp index 7edccde..a9a707e 100644 --- a/layers/gpuav/resources/gpuav_state_trackers.cpp +++ b/layers/gpuav/resources/gpuav_state_trackers.cpp
@@ -690,7 +690,8 @@ void TensorViewSubState::NotifyInvalidate(const vvl::StateObject::NodeList& invalid_nodes, bool unlink) { id_tracker.reset(); } -ShaderObjectSubState::ShaderObjectSubState(vvl::ShaderObject& obj) : vvl::ShaderObjectSubState(obj) {} +ShaderObjectSubState::ShaderObjectSubState(Validator& gpuav, vvl::ShaderObject& obj) + : vvl::ShaderObjectSubState(obj), gpuav_(gpuav) {} PipelineSubState::PipelineSubState(Validator& gpuav, vvl::Pipeline& pipeline) : vvl::PipelineSubState(pipeline), gpuav_(gpuav) {} @@ -793,4 +794,19 @@ uninstrumented_pipeline = pipeline; } +void ShaderObjectSubState::Destroy() { + if (stale_handle != VK_NULL_HANDLE) { + // vkDestroyShaderEXT 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.DestroyShaderEXT(gpuav_.device, stale_handle, nullptr); + } +} + +void ShaderObjectSubState::AddHandleToDestroy(VkShaderEXT shader) { + std::unique_lock<std::mutex> lock(mutex_); + assert(stale_handle == VK_NULL_HANDLE); + stale_handle = shader; +} + } // namespace gpuav
diff --git a/layers/gpuav/resources/gpuav_state_trackers.h b/layers/gpuav/resources/gpuav_state_trackers.h index 9829d1e..918fcb9 100644 --- a/layers/gpuav/resources/gpuav_state_trackers.h +++ b/layers/gpuav/resources/gpuav_state_trackers.h
@@ -44,6 +44,10 @@ struct LastBound; +namespace spirv { +struct Module; +} + namespace gpuav { class Validator; @@ -426,7 +430,13 @@ class ShaderObjectSubState : public vvl::ShaderObjectSubState { public: - explicit ShaderObjectSubState(vvl::ShaderObject &obj); + explicit ShaderObjectSubState(Validator& gpuav, vvl::ShaderObject& obj); + void Destroy() override; + + // Specifically for shaders instrumented post original creation: + // The old shader could be in use at time of instrumentation, + // so defer old pipeline destroy to Destroy() call. + void AddHandleToDestroy(VkShaderEXT shader); spirv::InstrumentationStatus instrumented_status; uint32_t unique_shader_id = 0; @@ -434,6 +444,15 @@ // We need to keep incase the user calls vkGetShaderBinaryDataEXT vku::safe_VkShaderCreateInfoEXT original_create_info; VkShaderEXT original_handle = VK_NULL_HANDLE; + + VkShaderEXT stale_handle = VK_NULL_HANDLE; + std::shared_ptr<::spirv::Module> original_module; + + private: + Validator& gpuav_; + // Multiple threads can record multiple commands using the same shader, + // so shader destruction has to be thread safe + mutable std::mutex mutex_{}; }; static inline ShaderObjectSubState &SubState(vvl::ShaderObject &obj) {
diff --git a/layers/state_tracker/shader_object_state.cpp b/layers/state_tracker/shader_object_state.cpp index 4d91cee..94ee50d 100644 --- a/layers/state_tracker/shader_object_state.cpp +++ b/layers/state_tracker/shader_object_state.cpp
@@ -50,4 +50,12 @@ } } +void ShaderObject::Destroy() { + for (auto& item : sub_states_) { + item.second->Destroy(); + } + sub_states_.clear(); + StateObject::Destroy(); +} + } // namespace vvl
diff --git a/layers/state_tracker/shader_object_state.h b/layers/state_tracker/shader_object_state.h index 4452d90..e4d9590 100644 --- a/layers/state_tracker/shader_object_state.h +++ b/layers/state_tracker/shader_object_state.h
@@ -42,6 +42,7 @@ struct ShaderObject : public StateObject, public SubStateManager<ShaderObjectSubState> { ShaderObject(DeviceState &dev_data, const VkShaderCreateInfoEXT &create_info_i, VkShaderEXT shader_object, std::shared_ptr<spirv::Module> &spirv_module); + void Destroy() override; const vku::safe_VkShaderCreateInfoEXT safe_create_info_ext; const VkShaderCreateInfoEXT &create_info_ext;
diff --git a/tests/unit/gpu_av_scoped.cpp b/tests/unit/gpu_av_scoped.cpp index a9599a6..b860e57 100644 --- a/tests/unit/gpu_av_scoped.cpp +++ b/tests/unit/gpu_av_scoped.cpp
@@ -350,6 +350,58 @@ m_errorMonitor->VerifyFound(); } +TEST_F(NegativeGpuAVScoped, SelectInstrumentedComputeShaderObjectRegex) { + TEST_DESCRIPTION("Selectively instrument a compute shader object for validation, using regexes"); + SetTargetApiVersion(VK_API_VERSION_1_2); + AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderObject); + 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 = {{"shader_object_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"; + + const vkt::ShaderEXT cs(*m_device, VK_SHADER_STAGE_COMPUTE_BIT, GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, cs_source), + &descriptor_set.layout_.handle()); + + VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper(); + name_info.objectType = VK_OBJECT_TYPE_SHADER_EXT; + name_info.pObjectName = "shader_object_foo"; + name_info.objectHandle = uint64_t(cs.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); + VkShaderStageFlagBits shader_stages[] = {VK_SHADER_STAGE_COMPUTE_BIT}; + vk::CmdBindShadersEXT(m_command_buffer, 1, shader_stages, &cs.handle()); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDispatch-None-08613", "shader_object_foo"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +} + TEST_F(NegativeGpuAVScoped, SelectInstrumentedComputePipelineCDLDump) { TEST_DESCRIPTION("Selectively instrument a compute pipeline for validation, using a CDL dump file as input"); SetTargetApiVersion(VK_API_VERSION_1_2);
diff --git a/tests/unit/gpu_av_scoped_positive.cpp b/tests/unit/gpu_av_scoped_positive.cpp index 1bd5ae5..b71f91f 100644 --- a/tests/unit/gpu_av_scoped_positive.cpp +++ b/tests/unit/gpu_av_scoped_positive.cpp
@@ -19,6 +19,7 @@ #include "pipeline_helper.h" #include "descriptor_helper.h" #include "shader_object_helper.h" +#include "utils/math_utils.h" class PositiveGpuAVScoped : public GpuAVTest {}; @@ -133,4 +134,64 @@ vk::CmdDispatchIndirect(m_command_buffer, indirect_dispatch_parameters_buffer, 0u); m_command_buffer.End(); -} \ No newline at end of file +} + +TEST_F(PositiveGpuAVScoped, SelectInstrumentedShaderObjectBinary) { + SetTargetApiVersion(VK_API_VERSION_1_2); + AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderObject); + + 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 = {{"shader_object_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()); + + OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}); + + const char cs_source[] = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data; + void main() { + Data.data[0] = 0u; + } + )glsl"; + + const vkt::ShaderEXT spirv_cs(*m_device, VK_SHADER_STAGE_COMPUTE_BIT, GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, cs_source), + &descriptor_set.layout_.handle()); + + size_t data_size = 0; + vk::GetShaderBinaryDataEXT(*m_device, spirv_cs, &data_size, nullptr); + if (data_size == 0) { + GTEST_SKIP() << "Driver returned no shader binary data"; + } + std::vector<uint8_t> binary(data_size + 15); // need 16-byte aligned pointers + void* binary_ptr = reinterpret_cast<void*>(Align(reinterpret_cast<uintptr_t>(binary.data()), (uintptr_t)16)); + vk::GetShaderBinaryDataEXT(*m_device, spirv_cs, &data_size, binary_ptr); + + VkShaderCreateInfoEXT create_info = vku::InitStructHelper(); + create_info.stage = VK_SHADER_STAGE_COMPUTE_BIT; + create_info.codeType = VK_SHADER_CODE_TYPE_BINARY_EXT; + create_info.codeSize = data_size; + create_info.pCode = binary_ptr; + create_info.pName = "main"; + create_info.setLayoutCount = 1u; + create_info.pSetLayouts = &descriptor_set.layout_.handle(); + + VkShaderEXT binary_cs = VK_NULL_HANDLE; + vk::CreateShadersEXT(*m_device, 1u, &create_info, nullptr, &binary_cs); + if (binary_cs == VK_NULL_HANDLE) { + GTEST_SKIP() << "Driver bug, not reparsing"; + } + + VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper(); + name_info.objectType = VK_OBJECT_TYPE_SHADER_EXT; + name_info.pObjectName = "shader_object_foo"; + name_info.objectHandle = uint64_t(binary_cs); + vk::SetDebugUtilsObjectNameEXT(device(), &name_info); + + vk::DestroyShaderEXT(*m_device, binary_cs, nullptr); +}