From 7b11eaf170ca65411594a451960bfd7ed089dfb5 Mon Sep 17 00:00:00 2001 From: Ming Zheng Date: Fri, 14 Jul 2023 17:23:43 -0400 Subject: [PATCH] Fix deferred operation handling error when using deferred operation object in command vkcreateraytracingpipelines , driver has two choices. One is driver proceed all workload in current thread within this command, another choice is deferring this command to other threads. The commit added handling to the second choice and fixed related errors on pipeline reading and capture/playback shader group handle error. Change-Id: Id4704502714b866211555d007e09dcefa69a4138 --- framework/decode/vulkan_consumer_base.h | 13 ++ .../vulkan_export_json_consumer_base.cpp | 25 +++ .../decode/vulkan_export_json_consumer_base.h | 12 ++ framework/decode/vulkan_object_info.h | 5 +- .../decode/vulkan_replay_consumer_base.cpp | 104 +++++++++- .../decode/vulkan_replay_consumer_base.h | 11 ++ .../custom_vulkan_api_call_encoders.cpp | 53 ++++-- .../encode/custom_vulkan_api_call_encoders.h | 1 + framework/encode/vulkan_capture_manager.cpp | 178 +++++++++++++++++- framework/encode/vulkan_capture_manager.h | 11 +- framework/encode/vulkan_handle_wrappers.h | 4 + framework/encode/vulkan_state_writer.cpp | 26 +++ framework/encode/vulkan_state_writer.h | 3 + .../generated_vulkan_api_call_encoders.cpp | 4 +- .../generated/generated_vulkan_consumer.h | 11 -- .../generated_vulkan_export_json_consumer.cpp | 24 --- .../generated_vulkan_export_json_consumer.h | 11 -- .../generated_vulkan_replay_consumer.cpp | 26 --- .../generated_vulkan_replay_consumer.h | 11 -- .../vulkan_generators/blacklists.json | 4 +- .../vulkan_generators/capture_overrides.json | 2 + .../vulkan_generators/replay_overrides.json | 1 - 22 files changed, 421 insertions(+), 119 deletions(-) diff --git a/framework/decode/vulkan_consumer_base.h b/framework/decode/vulkan_consumer_base.h index ce46bdb89b..7644fa23a3 100644 --- a/framework/decode/vulkan_consumer_base.h +++ b/framework/decode/vulkan_consumer_base.h @@ -1,6 +1,7 @@ /* ** Copyright (c) 2018-2020 Valve Corporation ** Copyright (c) 2018-2020 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -170,6 +171,18 @@ class VulkanConsumerBase format::HandleId descriptorUpdateTemplate, DescriptorUpdateTemplateDecoder* pData) {} + + virtual void Process_vkCreateRayTracingPipelinesKHR( + const ApiCallInfo& call_info, + VkResult returnValue, + format::HandleId device, + format::HandleId deferredOperation, + format::HandleId pipelineCache, + uint32_t createInfoCount, + StructPointerDecoder* pCreateInfos, + StructPointerDecoder* pAllocator, + HandlePointerDecoder* pPipelines) + {} }; GFXRECON_END_NAMESPACE(decode) diff --git a/framework/decode/vulkan_export_json_consumer_base.cpp b/framework/decode/vulkan_export_json_consumer_base.cpp index 0577d7cf73..c58d16546a 100644 --- a/framework/decode/vulkan_export_json_consumer_base.cpp +++ b/framework/decode/vulkan_export_json_consumer_base.cpp @@ -1,5 +1,6 @@ /* ** Copyright (c) 2022-2023 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -616,6 +617,30 @@ void VulkanExportJsonConsumerBase::Process_vkUpdateDescriptorSetWithTemplateKHR( WriteBlockEnd(); } +void VulkanExportJsonConsumerBase::Process_vkCreateRayTracingPipelinesKHR( + const ApiCallInfo& call_info, + VkResult returnValue, + format::HandleId device, + format::HandleId deferredOperation, + format::HandleId pipelineCache, + uint32_t createInfoCount, + StructPointerDecoder* pCreateInfos, + StructPointerDecoder* pAllocator, + HandlePointerDecoder* pPipelines) +{ + nlohmann::ordered_json& jdata = WriteApiCallStart(call_info, "vkCreateRayTracingPipelinesKHR"); + FieldToJson(jdata[NameReturn()], returnValue, json_options_); + auto& args = jdata[NameArgs()]; + HandleToJson(args["device"], device, json_options_); + HandleToJson(args["deferredOperation"], deferredOperation, json_options_); + HandleToJson(args["pipelineCache"], pipelineCache, json_options_); + FieldToJson(args["createInfoCount"], createInfoCount, json_options_); + FieldToJson(args["pCreateInfos"], pCreateInfos, json_options_); + FieldToJson(args["pAllocator"], pAllocator, json_options_); + HandleToJson(args["pPipelines"], pPipelines, json_options_); + WriteBlockEnd(); +} + void VulkanExportJsonConsumerBase::WriteBlockStart() { json_data_.clear(); // < Dominates profiling (1/2). diff --git a/framework/decode/vulkan_export_json_consumer_base.h b/framework/decode/vulkan_export_json_consumer_base.h index de0ad422ab..2546194a49 100644 --- a/framework/decode/vulkan_export_json_consumer_base.h +++ b/framework/decode/vulkan_export_json_consumer_base.h @@ -1,5 +1,6 @@ /* ** Copyright (c) 2022-2023 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -177,6 +178,17 @@ class VulkanExportJsonConsumerBase : public VulkanConsumer, public AnnotationHan format::HandleId descriptorUpdateTemplate, DescriptorUpdateTemplateDecoder* pData) override; + virtual void Process_vkCreateRayTracingPipelinesKHR( + const ApiCallInfo& call_info, + VkResult returnValue, + format::HandleId device, + format::HandleId deferredOperation, + format::HandleId pipelineCache, + uint32_t createInfoCount, + StructPointerDecoder* pCreateInfos, + StructPointerDecoder* pAllocator, + HandlePointerDecoder* pPipelines) override; + /// @brief Convert annotations, which are simple {type:enum, key:string, value:string} objects. virtual void ProcessAnnotation(uint64_t block_index, format::AnnotationType type, diff --git a/framework/decode/vulkan_object_info.h b/framework/decode/vulkan_object_info.h index fd7066002c..cf68af3dab 100644 --- a/framework/decode/vulkan_object_info.h +++ b/framework/decode/vulkan_object_info.h @@ -1,5 +1,6 @@ /* ** Copyright (c) 2019-2022 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -438,11 +439,13 @@ struct FramebufferInfo : public VulkanObjectInfo struct DeferredOperationKHRInfo : public VulkanObjectInfo { - VkResult join_state{ VK_NOT_READY }; + bool pending_state{ false }; // Record CreateRayTracingPipelinesKHR parameters for safety. std::vector record_modified_create_infos; std::vector> record_modified_pgroups; + std::vector replayPipelines; + std::vector capturePipelines; }; struct VideoSessionKHRInfo : VulkanObjectInfo diff --git a/framework/decode/vulkan_replay_consumer_base.cpp b/framework/decode/vulkan_replay_consumer_base.cpp index 7079e3baf0..a098668812 100644 --- a/framework/decode/vulkan_replay_consumer_base.cpp +++ b/framework/decode/vulkan_replay_consumer_base.cpp @@ -1,6 +1,7 @@ /* ** Copyright (c) 2018-2020 Valve Corporation ** Copyright (c) 2018-2023 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -6025,9 +6026,14 @@ VkResult VulkanReplayConsumerBase::OverrideCreateRayTracingPipelinesKHR( if (deferred_operation_info) { - deferred_operation_info->join_state = VK_NOT_READY; + deferred_operation_info->pending_state = true; deferred_operation_info->record_modified_create_infos.clear(); deferred_operation_info->record_modified_pgroups.clear(); + deferred_operation_info->replayPipelines.resize(createInfoCount); + deferred_operation_info->capturePipelines.resize(createInfoCount); + memcpy(deferred_operation_info->capturePipelines.data(), + pPipelines->GetPointer(), + createInfoCount * sizeof(VkPipeline)); } if (device_info->property_feature_info.feature_rayTracingPipelineShaderGroupHandleCaptureReplay) @@ -6092,7 +6098,33 @@ VkResult VulkanReplayConsumerBase::OverrideCreateRayTracingPipelinesKHR( createInfoCount, modified_create_infos.data(), in_pAllocator, - out_pPipelines); + deferred_operation_info->replayPipelines.data()); + if ((result == VK_SUCCESS) || (result == VK_OPERATION_NOT_DEFERRED_KHR) || + (result == VK_PIPELINE_COMPILE_REQUIRED_EXT)) + { + // The above return values mean the command is not deferred and driver will finish all workload in current + // thread. Therefore the created pipelines can be read and copied to out_pPipelines which will be + // referenced later. + // + // Note: + // Some pipelines might actually fail creation if the return value is VK_PIPELINE_COMPILE_REQUIRED_EXT. + // These failed pipelines will generate VK_NULL_HANDLE. + // + // If the return value is VK_OPERATION_DEFERRED_KHR, it means the command is deferred, and thus pipeline + // creation is not finished. Subsequent handling will be done by + // vkDeferredOperationJoinKHR/vkGetDeferredOperationResultKHR after pipeline creation is finished. + memcpy( + out_pPipelines, deferred_operation_info->replayPipelines.data(), createInfoCount * sizeof(VkPipeline)); + + if (deferred_operation_info) + { + // Eventhough vkCreateRayTracingPipelinesKHR was called with a valid deferred operation object, the + // driver may opt to not defer the command. In this case, set pending_state flag to false to skip + // vkDeferredOperationJoinKHR handling. + deferred_operation_info->pending_state = false; + } + } + if (deferred_operation_info) { deferred_operation_info->record_modified_create_infos = std::move(modified_create_infos); @@ -6122,8 +6154,9 @@ VkResult VulkanReplayConsumerBase::OverrideDeferredOperationJoinKHR(PFN_vkDeferr const DeviceInfo* device_info, DeferredOperationKHRInfo* deferred_operation_info) { - if (deferred_operation_info->join_state == VK_SUCCESS) + if (deferred_operation_info->pending_state == false) { + // The deferred operation object has no deferred command or its deferred command has been finished. return VK_SUCCESS; } @@ -6161,9 +6194,19 @@ VkResult VulkanReplayConsumerBase::OverrideDeferredOperationJoinKHR(PFN_vkDeferr j.get(); } - deferred_operation_info->join_state = VK_SUCCESS; + AddHandles(device_info->capture_id, + deferred_operation_info->capturePipelines.data(), + deferred_operation_info->capturePipelines.size(), + deferred_operation_info->replayPipelines.data(), + deferred_operation_info->replayPipelines.size(), + &VulkanObjectInfoTable::AddPipelineInfo); + + deferred_operation_info->pending_state = false; deferred_operation_info->record_modified_create_infos.clear(); deferred_operation_info->record_modified_pgroups.clear(); + deferred_operation_info->capturePipelines.clear(); + deferred_operation_info->replayPipelines.clear(); + return VK_SUCCESS; } @@ -6754,5 +6797,58 @@ void VulkanReplayConsumerBase::Process_vkUpdateDescriptorSetWithTemplateKHR(cons in_device, in_descriptorSet, in_descriptorUpdateTemplate, pData->GetPointer()); } +void VulkanReplayConsumerBase::Process_vkCreateRayTracingPipelinesKHR( + const ApiCallInfo& call_info, + VkResult returnValue, + format::HandleId device, + format::HandleId deferredOperation, + format::HandleId pipelineCache, + uint32_t createInfoCount, + StructPointerDecoder* pCreateInfos, + StructPointerDecoder* pAllocator, + HandlePointerDecoder* pPipelines) +{ + auto in_device = GetObjectInfoTable().GetDeviceInfo(device); + auto in_deferredOperation = GetObjectInfoTable().GetDeferredOperationKHRInfo(deferredOperation); + auto in_pipelineCache = GetObjectInfoTable().GetPipelineCacheInfo(pipelineCache); + MapStructArrayHandles(pCreateInfos->GetMetaStructPointer(), pCreateInfos->GetLength(), GetObjectInfoTable()); + + if (!pPipelines->IsNull()) + { + pPipelines->SetHandleLength(createInfoCount); + } + + std::vector handle_info(createInfoCount); + + for (size_t i = 0; i < createInfoCount; ++i) + { + pPipelines->SetConsumerData(i, &handle_info[i]); + } + + VkResult replay_result = + OverrideCreateRayTracingPipelinesKHR(GetDeviceTable(in_device->handle)->CreateRayTracingPipelinesKHR, + returnValue, + in_device, + in_deferredOperation, + in_pipelineCache, + createInfoCount, + pCreateInfos, + pAllocator, + pPipelines); + CheckResult("vkCreateRayTracingPipelinesKHR", returnValue, replay_result); + + if ((replay_result == VK_SUCCESS) || (replay_result == VK_OPERATION_NOT_DEFERRED_KHR) || + (replay_result == VK_PIPELINE_COMPILE_REQUIRED_EXT)) + { + AddHandles(device, + pPipelines->GetPointer(), + pPipelines->GetLength(), + pPipelines->GetHandlePointer(), + createInfoCount, + std::move(handle_info), + &VulkanObjectInfoTable::AddPipelineInfo); + } +} + GFXRECON_END_NAMESPACE(decode) GFXRECON_END_NAMESPACE(gfxrecon) diff --git a/framework/decode/vulkan_replay_consumer_base.h b/framework/decode/vulkan_replay_consumer_base.h index 673e830792..e42b1588df 100644 --- a/framework/decode/vulkan_replay_consumer_base.h +++ b/framework/decode/vulkan_replay_consumer_base.h @@ -1,6 +1,7 @@ /* ** Copyright (c) 2018-2020 Valve Corporation ** Copyright (c) 2018-2022 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -178,6 +179,16 @@ class VulkanReplayConsumerBase : public VulkanConsumer format::HandleId descriptorSet, format::HandleId descriptorUpdateTemplate, DescriptorUpdateTemplateDecoder* pData) override; + virtual void Process_vkCreateRayTracingPipelinesKHR( + const ApiCallInfo& call_info, + VkResult returnValue, + format::HandleId device, + format::HandleId deferredOperation, + format::HandleId pipelineCache, + uint32_t createInfoCount, + StructPointerDecoder* pCreateInfos, + StructPointerDecoder* pAllocator, + HandlePointerDecoder* pPipelines); protected: const VulkanObjectInfoTable& GetObjectInfoTable() const { return object_info_table_; } diff --git a/framework/encode/custom_vulkan_api_call_encoders.cpp b/framework/encode/custom_vulkan_api_call_encoders.cpp index 60daba9be3..bf25942964 100644 --- a/framework/encode/custom_vulkan_api_call_encoders.cpp +++ b/framework/encode/custom_vulkan_api_call_encoders.cpp @@ -1,6 +1,7 @@ /* ** Copyright (c) 2018-2020 Valve Corporation ** Copyright (c) 2018-2020 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -652,24 +653,40 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateRayTracingPipelinesKHR(VkDevice omit_output_data = true; } - auto encoder = VulkanCaptureManager::Get()->BeginTrackedApiCallCapture( - format::ApiCallId::ApiCall_vkCreateRayTracingPipelinesKHR); - if (encoder) - { - encoder->EncodeHandleValue(device); - encoder->EncodeHandleValue(deferredOperation); - encoder->EncodeHandleValue(pipelineCache); - encoder->EncodeUInt32Value(createInfoCount); - EncodeStructArray(encoder, pCreateInfos, createInfoCount); - EncodeStructPtr(encoder, pAllocator); - encoder->EncodeHandleArray(pPipelines, createInfoCount, omit_output_data); - encoder->EncodeEnumValue(result); - VulkanCaptureManager::Get() - ->EndGroupCreateApiCallCapture( - result, device, deferredOperation, createInfoCount, pPipelines, pCreateInfos); + auto device_wrapper = GetWrapper(device); + if ((result != VK_OPERATION_DEFERRED_KHR) || + (!device_wrapper->property_feature_info.feature_rayTracingPipelineShaderGroupHandleCaptureReplay)) + { + // If the operation is not deferred by driver. or the system doesn't support + // rayTracingPipelineShaderGroupHandleCaptureReplay, we don't need to delay writing the block of + // vkCreateRayTracingPipelinesKHR to the capture file. + // + // If the operation is deferred by driver and the system supports + // rayTracingPipelineShaderGroupHandleCaptureReplay, we will need to make sure opaque capture replay data for + // pipeline shader group handles are ready when calling vkCreateRayTracingPipelinesKHR during replay. However, + // opaque capture replay data for pipeline shader group handles needs pipeline creation to be finished so that + // vkGetRayTracingCaptureReplayShaderGroupHandlesKHR may be used. For this reason, we will delay the writing of + // vkCreateRayTracingPipelinesKHR block to capture file until the deferred operation is finished. + + auto encoder = VulkanCaptureManager::Get()->BeginTrackedApiCallCapture( + format::ApiCallId::ApiCall_vkCreateRayTracingPipelinesKHR); + if (encoder) + { + encoder->EncodeHandleValue(device); + encoder->EncodeHandleValue(deferredOperation); + encoder->EncodeHandleValue(pipelineCache); + encoder->EncodeUInt32Value(createInfoCount); + EncodeStructArray(encoder, pCreateInfos, createInfoCount); + EncodeStructPtr(encoder, pAllocator); + encoder->EncodeHandleArray(pPipelines, createInfoCount, omit_output_data); + encoder->EncodeEnumValue(result); + VulkanCaptureManager::Get() + ->EndGroupCreateApiCallCapture( + result, device, deferredOperation, createInfoCount, pPipelines, pCreateInfos); + } } CustomEncoderPostCall::Dispatch( diff --git a/framework/encode/custom_vulkan_api_call_encoders.h b/framework/encode/custom_vulkan_api_call_encoders.h index fdbb9ff9b4..349699b71a 100644 --- a/framework/encode/custom_vulkan_api_call_encoders.h +++ b/framework/encode/custom_vulkan_api_call_encoders.h @@ -1,6 +1,7 @@ /* ** Copyright (c) 2018-2020 Valve Corporation ** Copyright (c) 2018-2020 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), diff --git a/framework/encode/vulkan_capture_manager.cpp b/framework/encode/vulkan_capture_manager.cpp index f06e67d72e..da57b242d2 100644 --- a/framework/encode/vulkan_capture_manager.cpp +++ b/framework/encode/vulkan_capture_manager.cpp @@ -1,7 +1,7 @@ /* ** Copyright (c) 2018-2021 Valve Corporation ** Copyright (c) 2018-2021 LunarG, Inc. -** Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved. +** Copyright (c) 2019-2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -24,6 +24,7 @@ #include "project_version.h" +#include "encode/struct_pointer_encoder.h" #include "encode/vulkan_capture_manager.h" #include "encode/vulkan_handle_wrapper_util.h" @@ -1181,6 +1182,8 @@ VulkanCaptureManager::OverrideCreateRayTracingPipelinesKHR(VkDevice } deferred_operation_wrapper->create_infos.resize(createInfoCount); deferred_operation_wrapper->pipelines.resize(createInfoCount); + deferred_operation_wrapper->pPipelines = pPipelines; + deferred_operation_wrapper->pipelineCache = pipelineCache; } else { @@ -1211,7 +1214,24 @@ VulkanCaptureManager::OverrideCreateRayTracingPipelinesKHR(VkDevice deferred_operation_wrapper->p_allocator, deferred_operation_wrapper->pipelines.data()); - std::memcpy(pPipelines, deferred_operation_wrapper->pipelines.data(), sizeof(VkPipeline) * createInfoCount); + if (result == VK_OPERATION_NOT_DEFERRED_KHR) + { + // VK_OPERATION_NOT_DEFERRED_KHR means the operation successfully completed immediately, so here we copy + // the created pipelines to original array which is used to store them by target application. + // + // Note: + // VK_OPERATION_DEFERRED_KHR means the operation is successfully deferred, but the pipeline + // creation might not be finished. We must therefore lean on + // vkDeferredOperationJoinKHR/vkGetDeferredOperationResultKHR to get the final result. If the + // result indicated the operation has finished, then the created pipelines are ready for use. + std::memcpy( + pPipelines, deferred_operation_wrapper->pipelines.data(), sizeof(VkPipeline) * createInfoCount); + } + else if (result == VK_OPERATION_DEFERRED_KHR) + { + const std::lock_guard lock(deferred_operation_mutex); + deferred_operation_wrapper->pending_state = true; + } } else { @@ -1243,8 +1263,18 @@ VulkanCaptureManager::OverrideCreateRayTracingPipelinesKHR(VkDevice deferred_operation_wrapper->create_infos.data(), deferred_operation_wrapper->p_allocator, deferred_operation_wrapper->pipelines.data()); - - std::memcpy(pPipelines, deferred_operation_wrapper->pipelines.data(), sizeof(VkPipeline) * createInfoCount); + if (result == VK_OPERATION_NOT_DEFERRED_KHR) + { + // If the driver doesn't defer the command, and instead completed the operation immediately, we copy the + // created pipelines to original array which is used to store them by target application. + std::memcpy( + pPipelines, deferred_operation_wrapper->pipelines.data(), sizeof(VkPipeline) * createInfoCount); + } + else if (result == VK_OPERATION_DEFERRED_KHR) + { + const std::lock_guard lock(deferred_operation_mutex); + deferred_operation_wrapper->pending_state = true; + } } else { @@ -1257,10 +1287,11 @@ VulkanCaptureManager::OverrideCreateRayTracingPipelinesKHR(VkDevice pPipelines); } } - if (((result == VK_SUCCESS) || (result == VK_OPERATION_DEFERRED_KHR) || - (result == VK_OPERATION_NOT_DEFERRED_KHR)) && - (pPipelines != nullptr)) + + if (((result == VK_SUCCESS) || (result == VK_OPERATION_NOT_DEFERRED_KHR)) && (pPipelines != nullptr)) { + // If the return result show the creation is successfully finished, we do the following process. + CreateWrappedHandles( device, deferredOperation, pPipelines, createInfoCount, GetUniqueId); @@ -1297,6 +1328,139 @@ VulkanCaptureManager::OverrideCreateRayTracingPipelinesKHR(VkDevice return result; } +void VulkanCaptureManager::DeferredOperationPostProcess(VkDevice device, + VkDeferredOperationKHR deferredOperation, + bool capture_manager_tracking) +{ + const std::lock_guard lock(deferred_operation_mutex); + VkResult result = VK_SUCCESS; + auto deferred_operation_wrapper = GetWrapper(deferredOperation); + auto device_wrapper = GetWrapper(device); + const DeviceTable* device_table = GetDeviceTable(device); + + GFXRECON_ASSERT(device_table != nullptr); + + if ((deferred_operation_wrapper != nullptr) && (deferred_operation_wrapper->pending_state)) + { + deferred_operation_wrapper->pending_state = false; + uint32_t create_info_count = deferred_operation_wrapper->create_infos.size(); + std::memcpy(deferred_operation_wrapper->pPipelines, + deferred_operation_wrapper->pipelines.data(), + sizeof(VkPipeline) * deferred_operation_wrapper->create_infos.size()); + + CreateWrappedHandles( + device, deferredOperation, deferred_operation_wrapper->pPipelines, create_info_count, GetUniqueId); + + for (uint32_t i = 0; i < create_info_count; ++i) + { + auto pipeline_wrapper = GetWrapper(deferred_operation_wrapper->pPipelines[i]); + + if (deferred_operation_wrapper) + { + pipeline_wrapper->deferred_operation.handle_id = deferred_operation_wrapper->handle_id; + pipeline_wrapper->deferred_operation.create_call_id = deferred_operation_wrapper->create_call_id; + pipeline_wrapper->deferred_operation.create_parameters = deferred_operation_wrapper->create_parameters; + } + + if (device_wrapper->property_feature_info.feature_rayTracingPipelineShaderGroupHandleCaptureReplay) + { + const uint32_t data_size = + device_wrapper->property_feature_info.property_shaderGroupHandleCaptureReplaySize * + deferred_operation_wrapper->create_infos[i].groupCount; + + std::vector data(data_size); + device_table->GetRayTracingCaptureReplayShaderGroupHandlesKHR( + device_wrapper->handle, + pipeline_wrapper->handle, + 0, + deferred_operation_wrapper->create_infos[i].groupCount, + data_size, + data.data()); + + WriteSetRayTracingShaderGroupHandlesCommand( + device_wrapper->handle_id, pipeline_wrapper->handle_id, data_size, data.data()); + + if (capture_manager_tracking == true) + { + state_tracker_->TrackRayTracingShaderGroupHandles( + device, deferred_operation_wrapper->pPipelines[i], data_size, data.data()); + } + } + } + + // When the command vkCreateRayTracingPipelinesKHR is deferred at capture time, the created pipelines might not + // be ready on the return of the API call, because the pipeline creation workload might not be finished. But for + // replay time, we must guarantee the data relevant to vkGetRayTracingCaptureReplayShaderGroupHandlesKHR is + // ready before calling vkCreateRaytracingPipelines so shader group handles during playback are the same with + // capture time. The special handling needed here that when the command vkCreateRayTracingPipelinesKHR is + // deferred, the writing of its block will be delayed writing to file, until it is confirmed that the deferred + // command is finished. + auto encoder = BeginTrackedApiCallCapture(format::ApiCallId::ApiCall_vkCreateRayTracingPipelinesKHR); + + if (encoder) + { + encoder->EncodeHandleValue(device); + encoder->EncodeHandleValue(deferredOperation); + encoder->EncodeHandleValue(deferred_operation_wrapper->pipelineCache); + encoder->EncodeUInt32Value(create_info_count); + EncodeStructArray(encoder, deferred_operation_wrapper->create_infos.data(), create_info_count); + EncodeStructPtr(encoder, deferred_operation_wrapper->p_allocator); + encoder->EncodeHandleArray( + deferred_operation_wrapper->pPipelines, create_info_count, false); + encoder->EncodeEnumValue(VK_OPERATION_DEFERRED_KHR); + EndGroupCreateApiCallCapture( + result, + device, + deferredOperation, + create_info_count, + deferred_operation_wrapper->pPipelines, + deferred_operation_wrapper->create_infos.data()); + } + } +} + +VkResult VulkanCaptureManager::OverrideDeferredOperationJoinKHR(VkDevice device, VkDeferredOperationKHR operation) +{ + auto device_table = GetDeviceTable(device); + GFXRECON_ASSERT(device_table != nullptr); + VkResult result = device_table->DeferredOperationJoinKHR(device, operation); + + if (result == VK_SUCCESS) + { + // The deferred operation done and we continue to get the deferred command return value. + VkResult deferred_command_result = device_table->GetDeferredOperationResultKHR(device, operation); + + if (deferred_command_result == VK_SUCCESS) + { + // The deferred command return VK_SUCCESS + DeferredOperationPostProcess(device, operation, (GetCaptureMode() & kModeTrack) == kModeTrack); + } + } + + return result; +} + +VkResult VulkanCaptureManager::OverrideGetDeferredOperationResultKHR(VkDevice device, VkDeferredOperationKHR operation) +{ + auto device_table = GetDeviceTable(device); + GFXRECON_ASSERT(device_table != nullptr); + VkResult result = device_table->GetDeferredOperationResultKHR(device, operation); + + if (result == VK_SUCCESS) + { + // There are the following two cases with VK_SUCCESS for vkGetDeferredOperationResultKHR. Both are covered by + // DeferredOperationPostProcess: + // 1. The deferred operation finished and returned VK_SUCCESS. + // 2. No command has been deferred on the deferred operation object. + DeferredOperationPostProcess(device, operation, (GetCaptureMode() & kModeTrack) == kModeTrack); + } + + return result; +} + void VulkanCaptureManager::OverrideGetPhysicalDeviceQueueFamilyProperties( VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, diff --git a/framework/encode/vulkan_capture_manager.h b/framework/encode/vulkan_capture_manager.h index 6ab78265d7..00c9e88c53 100644 --- a/framework/encode/vulkan_capture_manager.h +++ b/framework/encode/vulkan_capture_manager.h @@ -1,7 +1,7 @@ /* ** Copyright (c) 2018-2021 Valve Corporation ** Copyright (c) 2018-2021 LunarG, Inc. -** Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved. +** Copyright (c) 2019-2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -291,6 +291,14 @@ class VulkanCaptureManager : public CaptureManager const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); + VkResult OverrideDeferredOperationJoinKHR(VkDevice device, VkDeferredOperationKHR operation); + + VkResult OverrideGetDeferredOperationResultKHR(VkDevice device, VkDeferredOperationKHR operation); + + void DeferredOperationPostProcess(VkDevice device, + VkDeferredOperationKHR deferredOperation, + bool capture_manager_tracking); + void OverrideGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); @@ -1249,6 +1257,7 @@ class VulkanCaptureManager : public CaptureManager std::set mapped_memory_; // Track mapped memory for unassisted tracking mode. std::unique_ptr state_tracker_; HardwareBufferMap hardware_buffers_; + std::mutex deferred_operation_mutex; }; GFXRECON_END_NAMESPACE(encode) diff --git a/framework/encode/vulkan_handle_wrappers.h b/framework/encode/vulkan_handle_wrappers.h index 731b16abb6..ddbc98f1df 100644 --- a/framework/encode/vulkan_handle_wrappers.h +++ b/framework/encode/vulkan_handle_wrappers.h @@ -1,5 +1,6 @@ /* ** Copyright (c) 2019-2020 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -327,6 +328,9 @@ struct DeferredOperationKHRWrapper : public HandleWrapper pipelines; + VkPipeline* pPipelines; + VkPipelineCache pipelineCache; + bool pending_state = false; }; struct DescriptorUpdateTemplateWrapper : public HandleWrapper diff --git a/framework/encode/vulkan_state_writer.cpp b/framework/encode/vulkan_state_writer.cpp index 8b9af07f71..2d80ef3a6a 100644 --- a/framework/encode/vulkan_state_writer.cpp +++ b/framework/encode/vulkan_state_writer.cpp @@ -1,5 +1,6 @@ /* ** Copyright (c) 2019-2020 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -565,6 +566,7 @@ void VulkanStateWriter::WritePipelineState(const VulkanStateTable& state_table) std::unordered_map temp_layouts; std::unordered_map temp_ds_layouts; std::unordered_map temp_deferred_operations; + std::unordered_map temp_deferred_operation_join_command; // First pass over pipeline table to sort pipelines by type and determine which dependencies need to be created // temporarily. @@ -643,6 +645,12 @@ void VulkanStateWriter::WritePipelineState(const VulkanStateTable& state_table) if (inserted.second) { WriteFunctionCall(wrapper->deferred_operation.create_call_id, create_parameters); + + // If a raytracing pipeline was created with a deferred operation object, we also need to generate a + // deferred operation join command, so the deferred command can finish. These join commands must be + // after calling vkCreateRayTracingPipelinesKHR. Here we record these deferred operations and their + // related device id to generate the join command later. + temp_deferred_operation_join_command[wrapper->deferred_operation.handle_id] = wrapper->device_id; } // TODO: It shouldn't destroy VkDeferredOperation after vkCreateRayTracingPipelinesKHR because it will // run vkDeferredOperationJoinKHR and vkGetDeferredOperationResultKHR after @@ -728,6 +736,11 @@ void VulkanStateWriter::WritePipelineState(const VulkanStateTable& state_table) WriteFunctionCall(format::ApiCall_vkCreateRayTracingPipelinesKHR, entry); } + for (const auto& entry : temp_deferred_operation_join_command) + { + WriteDeferredOperationJoinCommand(entry.second, entry.first); + } + // Temporary object destruction. for (const auto& entry : temp_shaders) { @@ -1089,6 +1102,19 @@ void VulkanStateWriter::WriteAccelerationStructureKHRState(const VulkanStateTabl }); } +void VulkanStateWriter::WriteDeferredOperationJoinCommand(format::HandleId device_id, + format::HandleId deferred_operation_id) +{ + const VkResult result = VK_SUCCESS; + + encoder_.EncodeHandleIdValue(device_id); + encoder_.EncodeHandleIdValue(deferred_operation_id); + encoder_.EncodeEnumValue(result); + + WriteFunctionCall(format::ApiCallId::ApiCall_vkDeferredOperationJoinKHR, ¶meter_stream_); + parameter_stream_.Reset(); +} + void VulkanStateWriter::ProcessHardwareBuffer(format::HandleId memory_id, AHardwareBuffer* hardware_buffer, VkDeviceSize allocation_size) diff --git a/framework/encode/vulkan_state_writer.h b/framework/encode/vulkan_state_writer.h index f64dbb9b9d..c0801670bf 100644 --- a/framework/encode/vulkan_state_writer.h +++ b/framework/encode/vulkan_state_writer.h @@ -1,5 +1,6 @@ /* ** Copyright (c) 2019-2021 LunarG, Inc. +** Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), @@ -135,6 +136,8 @@ class VulkanStateWriter void WriteAccelerationStructureKHRState(const VulkanStateTable& state_table); + void WriteDeferredOperationJoinCommand(format::HandleId device_id, format::HandleId deferred_operation_id); + void ProcessHardwareBuffer(format::HandleId memory_id, AHardwareBuffer* hardware_buffer, VkDeviceSize allocation_size); diff --git a/framework/generated/generated_vulkan_api_call_encoders.cpp b/framework/generated/generated_vulkan_api_call_encoders.cpp index b890cbd3d7..6a9de5a672 100644 --- a/framework/generated/generated_vulkan_api_call_encoders.cpp +++ b/framework/generated/generated_vulkan_api_call_encoders.cpp @@ -12322,7 +12322,7 @@ VKAPI_ATTR VkResult VKAPI_CALL GetDeferredOperationResultKHR( CustomEncoderPreCall::Dispatch(VulkanCaptureManager::Get(), device, operation); - VkResult result = GetDeviceTable(device)->GetDeferredOperationResultKHR(device, operation); + VkResult result = VulkanCaptureManager::Get()->OverrideGetDeferredOperationResultKHR(device, operation); auto encoder = VulkanCaptureManager::Get()->BeginApiCallCapture(format::ApiCallId::ApiCall_vkGetDeferredOperationResultKHR); if (encoder) @@ -12356,7 +12356,7 @@ VKAPI_ATTR VkResult VKAPI_CALL DeferredOperationJoinKHR( CustomEncoderPreCall::Dispatch(VulkanCaptureManager::Get(), device, operation); - VkResult result = GetDeviceTable(device)->DeferredOperationJoinKHR(device, operation); + VkResult result = VulkanCaptureManager::Get()->OverrideDeferredOperationJoinKHR(device, operation); auto encoder = VulkanCaptureManager::Get()->BeginApiCallCapture(format::ApiCallId::ApiCall_vkDeferredOperationJoinKHR); if (encoder) diff --git a/framework/generated/generated_vulkan_consumer.h b/framework/generated/generated_vulkan_consumer.h index 7fba00ab0e..3a6907cd24 100644 --- a/framework/generated/generated_vulkan_consumer.h +++ b/framework/generated/generated_vulkan_consumer.h @@ -4054,17 +4054,6 @@ class VulkanConsumer : public VulkanConsumerBase uint32_t height, uint32_t depth) {} - virtual void Process_vkCreateRayTracingPipelinesKHR( - const ApiCallInfo& call_info, - VkResult returnValue, - format::HandleId device, - format::HandleId deferredOperation, - format::HandleId pipelineCache, - uint32_t createInfoCount, - StructPointerDecoder* pCreateInfos, - StructPointerDecoder* pAllocator, - HandlePointerDecoder* pPipelines) {} - virtual void Process_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( const ApiCallInfo& call_info, VkResult returnValue, diff --git a/framework/generated/generated_vulkan_export_json_consumer.cpp b/framework/generated/generated_vulkan_export_json_consumer.cpp index 2e1f172d81..3cd9df9963 100644 --- a/framework/generated/generated_vulkan_export_json_consumer.cpp +++ b/framework/generated/generated_vulkan_export_json_consumer.cpp @@ -9347,30 +9347,6 @@ void VulkanExportJsonConsumer::Process_vkCmdTraceRaysKHR( WriteBlockEnd(); } -void VulkanExportJsonConsumer::Process_vkCreateRayTracingPipelinesKHR( - const ApiCallInfo& call_info, - VkResult returnValue, - format::HandleId device, - format::HandleId deferredOperation, - format::HandleId pipelineCache, - uint32_t createInfoCount, - StructPointerDecoder* pCreateInfos, - StructPointerDecoder* pAllocator, - HandlePointerDecoder* pPipelines) -{ - nlohmann::ordered_json& jdata = WriteApiCallStart(call_info, "vkCreateRayTracingPipelinesKHR"); - FieldToJson(jdata[NameReturn()], returnValue, json_options_); - auto& args = jdata[NameArgs()]; - HandleToJson(args["device"], device, json_options_); - HandleToJson(args["deferredOperation"], deferredOperation, json_options_); - HandleToJson(args["pipelineCache"], pipelineCache, json_options_); - FieldToJson(args["createInfoCount"], createInfoCount, json_options_); - FieldToJson(args["pCreateInfos"], pCreateInfos, json_options_); - FieldToJson(args["pAllocator"], pAllocator, json_options_); - HandleToJson(args["pPipelines"], pPipelines, json_options_); - WriteBlockEnd(); -} - void VulkanExportJsonConsumer::Process_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( const ApiCallInfo& call_info, VkResult returnValue, diff --git a/framework/generated/generated_vulkan_export_json_consumer.h b/framework/generated/generated_vulkan_export_json_consumer.h index fcb0e33098..f793d0fb64 100644 --- a/framework/generated/generated_vulkan_export_json_consumer.h +++ b/framework/generated/generated_vulkan_export_json_consumer.h @@ -4012,17 +4012,6 @@ class VulkanExportJsonConsumer : public VulkanExportJsonConsumerBase uint32_t height, uint32_t depth) override; - virtual void Process_vkCreateRayTracingPipelinesKHR( - const ApiCallInfo& call_info, - VkResult returnValue, - format::HandleId device, - format::HandleId deferredOperation, - format::HandleId pipelineCache, - uint32_t createInfoCount, - StructPointerDecoder* pCreateInfos, - StructPointerDecoder* pAllocator, - HandlePointerDecoder* pPipelines) override; - virtual void Process_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( const ApiCallInfo& call_info, VkResult returnValue, diff --git a/framework/generated/generated_vulkan_replay_consumer.cpp b/framework/generated/generated_vulkan_replay_consumer.cpp index 6711ad6e0d..8aad3f722a 100644 --- a/framework/generated/generated_vulkan_replay_consumer.cpp +++ b/framework/generated/generated_vulkan_replay_consumer.cpp @@ -8745,32 +8745,6 @@ void VulkanReplayConsumer::Process_vkCmdTraceRaysKHR( GetDeviceTable(in_commandBuffer)->CmdTraceRaysKHR(in_commandBuffer, in_pRaygenShaderBindingTable, in_pMissShaderBindingTable, in_pHitShaderBindingTable, in_pCallableShaderBindingTable, width, height, depth); } -void VulkanReplayConsumer::Process_vkCreateRayTracingPipelinesKHR( - const ApiCallInfo& call_info, - VkResult returnValue, - format::HandleId device, - format::HandleId deferredOperation, - format::HandleId pipelineCache, - uint32_t createInfoCount, - StructPointerDecoder* pCreateInfos, - StructPointerDecoder* pAllocator, - HandlePointerDecoder* pPipelines) -{ - auto in_device = GetObjectInfoTable().GetDeviceInfo(device); - auto in_deferredOperation = GetObjectInfoTable().GetDeferredOperationKHRInfo(deferredOperation); - auto in_pipelineCache = GetObjectInfoTable().GetPipelineCacheInfo(pipelineCache); - - MapStructArrayHandles(pCreateInfos->GetMetaStructPointer(), pCreateInfos->GetLength(), GetObjectInfoTable()); - if (!pPipelines->IsNull()) { pPipelines->SetHandleLength(createInfoCount); } - std::vector handle_info(createInfoCount); - for (size_t i = 0; i < createInfoCount; ++i) { pPipelines->SetConsumerData(i, &handle_info[i]); } - - VkResult replay_result = OverrideCreateRayTracingPipelinesKHR(GetDeviceTable(in_device->handle)->CreateRayTracingPipelinesKHR, returnValue, in_device, in_deferredOperation, in_pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); - CheckResult("vkCreateRayTracingPipelinesKHR", returnValue, replay_result); - - AddHandles(device, pPipelines->GetPointer(), pPipelines->GetLength(), pPipelines->GetHandlePointer(), createInfoCount, std::move(handle_info), &VulkanObjectInfoTable::AddPipelineInfo); -} - void VulkanReplayConsumer::Process_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( const ApiCallInfo& call_info, VkResult returnValue, diff --git a/framework/generated/generated_vulkan_replay_consumer.h b/framework/generated/generated_vulkan_replay_consumer.h index 1fbbbcb735..d2e03c26a1 100644 --- a/framework/generated/generated_vulkan_replay_consumer.h +++ b/framework/generated/generated_vulkan_replay_consumer.h @@ -4054,17 +4054,6 @@ class VulkanReplayConsumer : public VulkanReplayConsumerBase uint32_t height, uint32_t depth) override; - virtual void Process_vkCreateRayTracingPipelinesKHR( - const ApiCallInfo& call_info, - VkResult returnValue, - format::HandleId device, - format::HandleId deferredOperation, - format::HandleId pipelineCache, - uint32_t createInfoCount, - StructPointerDecoder* pCreateInfos, - StructPointerDecoder* pAllocator, - HandlePointerDecoder* pPipelines) override; - virtual void Process_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( const ApiCallInfo& call_info, VkResult returnValue, diff --git a/framework/generated/vulkan_generators/blacklists.json b/framework/generated/vulkan_generators/blacklists.json index 365379f5ca..e56eefe4b6 100644 --- a/framework/generated/vulkan_generators/blacklists.json +++ b/framework/generated/vulkan_generators/blacklists.json @@ -11,7 +11,8 @@ "vkUpdateDescriptorSetWithTemplateKHR", "vkCmdPushDescriptorSetWithTemplateKHR", "vkBuildAccelerationStructuresKHR", - "vkCopyAccelerationStructureKHR" + "vkCopyAccelerationStructureKHR", + "vkCreateRayTracingPipelinesKHR" ], "functions-encoder": [ "vkCreateComputePipelines", @@ -20,7 +21,6 @@ "vkCreateRayTracingPipelinesKHR" ], "functions-decoder": [ - "vkCreateRayTracingPipelinesKHR", "vkDeferredOperationJoinKHR" ], "structures": [ diff --git a/framework/generated/vulkan_generators/capture_overrides.json b/framework/generated/vulkan_generators/capture_overrides.json index 2b6de71129..8282197579 100644 --- a/framework/generated/vulkan_generators/capture_overrides.json +++ b/framework/generated/vulkan_generators/capture_overrides.json @@ -7,6 +7,8 @@ "vkAllocateMemory": "VulkanCaptureManager::Get()->OverrideAllocateMemory", "vkGetPhysicalDeviceToolPropertiesEXT": "VulkanCaptureManager::Get()->OverrideGetPhysicalDeviceToolPropertiesEXT", "vkCreateAccelerationStructureKHR": "VulkanCaptureManager::Get()->OverrideCreateAccelerationStructureKHR", + "vkGetDeferredOperationResultKHR": "VulkanCaptureManager::Get()->OverrideGetDeferredOperationResultKHR", + "vkDeferredOperationJoinKHR": "VulkanCaptureManager::Get()->OverrideDeferredOperationJoinKHR", "vkGetPhysicalDeviceQueueFamilyProperties": "VulkanCaptureManager::Get()->OverrideGetPhysicalDeviceQueueFamilyProperties", "vkGetPhysicalDeviceQueueFamilyProperties2": "VulkanCaptureManager::Get()->OverrideGetPhysicalDeviceQueueFamilyProperties2", "vkGetPhysicalDeviceQueueFamilyProperties2KHR": "VulkanCaptureManager::Get()->OverrideGetPhysicalDeviceQueueFamilyProperties2KHR" diff --git a/framework/generated/vulkan_generators/replay_overrides.json b/framework/generated/vulkan_generators/replay_overrides.json index 55ecb02071..d27e2bb0c2 100644 --- a/framework/generated/vulkan_generators/replay_overrides.json +++ b/framework/generated/vulkan_generators/replay_overrides.json @@ -79,7 +79,6 @@ "vkDestroySurfaceKHR": "OverrideDestroySurfaceKHR", "vkCreateAccelerationStructureKHR": "OverrideCreateAccelerationStructureKHR", "vkGetRandROutputDisplayEXT": "OverrideGetRandROutputDisplayEXT", - "vkCreateRayTracingPipelinesKHR": "OverrideCreateRayTracingPipelinesKHR", "vkGetBufferDeviceAddress": "OverrideGetBufferDeviceAddress", "vkGetBufferDeviceAddressKHR": "OverrideGetBufferDeviceAddress", "vkGetAccelerationStructureDeviceAddressKHR": "OverrideGetAccelerationStructureDeviceAddressKHR",