diff --git a/android/framework/decode/CMakeLists.txt b/android/framework/decode/CMakeLists.txt index d7052f26b..fdc425530 100644 --- a/android/framework/decode/CMakeLists.txt +++ b/android/framework/decode/CMakeLists.txt @@ -28,6 +28,8 @@ target_sources(gfxrecon_decode ${GFXRECON_SOURCE_DIR}/framework/decode/handle_pointer_decoder.h ${GFXRECON_SOURCE_DIR}/framework/decode/json_writer.h ${GFXRECON_SOURCE_DIR}/framework/decode/json_writer.cpp + ${GFXRECON_SOURCE_DIR}/framework/decode/mark_injected_commands.h + ${GFXRECON_SOURCE_DIR}/framework/decode/mark_injected_commands.cpp ${GFXRECON_SOURCE_DIR}/framework/decode/pointer_decoder_base.h ${GFXRECON_SOURCE_DIR}/framework/decode/pointer_decoder.h ${GFXRECON_SOURCE_DIR}/framework/decode/portability.h diff --git a/framework/decode/CMakeLists.txt b/framework/decode/CMakeLists.txt index 29a910fc3..e15317943 100644 --- a/framework/decode/CMakeLists.txt +++ b/framework/decode/CMakeLists.txt @@ -74,6 +74,8 @@ target_sources(gfxrecon_decode ${CMAKE_CURRENT_LIST_DIR}/json_writer.cpp ${CMAKE_CURRENT_LIST_DIR}/decode_json_util.h ${CMAKE_CURRENT_LIST_DIR}/decode_json_util.cpp + ${CMAKE_CURRENT_LIST_DIR}/mark_injected_commands.h + ${CMAKE_CURRENT_LIST_DIR}/mark_injected_commands.cpp ${CMAKE_CURRENT_LIST_DIR}/pointer_decoder_base.h ${CMAKE_CURRENT_LIST_DIR}/pointer_decoder.h ${CMAKE_CURRENT_LIST_DIR}/portability.h diff --git a/framework/decode/file_processor.cpp b/framework/decode/file_processor.cpp index ad7cba467..9c219171d 100644 --- a/framework/decode/file_processor.cpp +++ b/framework/decode/file_processor.cpp @@ -47,7 +47,7 @@ const uint32_t kFirstFrame = 0; FileProcessor::FileProcessor() : current_frame_number_(kFirstFrame), error_state_(kErrorInvalidFileDescriptor), bytes_read_(0), annotation_handler_(nullptr), compressor_(nullptr), block_index_(0), api_call_index_(0), block_limit_(0), - capture_uses_frame_markers_(false), first_frame_(kFirstFrame + 1) + capture_uses_frame_markers_(false), first_frame_(kFirstFrame + 1), loading_trimmed_capture_state_(false) {} FileProcessor::FileProcessor(uint64_t block_limit) : FileProcessor() @@ -2167,11 +2167,13 @@ bool FileProcessor::ProcessStateMarker(const format::BlockHeader& block_header, if (marker_type == format::kBeginMarker) { GFXRECON_LOG_INFO("Loading state for captured frame %" PRId64, frame_number); + loading_trimmed_capture_state_ = true; } else if (marker_type == format::kEndMarker) { GFXRECON_LOG_INFO("Finished loading state for captured frame %" PRId64, frame_number); - first_frame_ = frame_number; + first_frame_ = frame_number; + loading_trimmed_capture_state_ = false; } for (auto decoder : decoders_) diff --git a/framework/decode/file_processor.h b/framework/decode/file_processor.h index dfced5c17..c8cf0c12a 100644 --- a/framework/decode/file_processor.h +++ b/framework/decode/file_processor.h @@ -98,6 +98,10 @@ class FileProcessor uint32_t GetCurrentFrameNumber() const { return current_frame_number_; } + uint64_t GetCurrentBlockIndex() const { return block_index_; } + + bool GetLoadingTrimmedState() const { return loading_trimmed_capture_state_; } + uint64_t GetNumBytesRead() const { return bytes_read_; } Error GetErrorState() const { return error_state_; } @@ -238,6 +242,7 @@ class FileProcessor bool enable_print_block_info_{ false }; int64_t block_index_from_{ 0 }; int64_t block_index_to_{ 0 }; + bool loading_trimmed_capture_state_; struct ActiveFiles { diff --git a/framework/decode/mark_injected_commands.cpp b/framework/decode/mark_injected_commands.cpp new file mode 100644 index 000000000..72b1acf1a --- /dev/null +++ b/framework/decode/mark_injected_commands.cpp @@ -0,0 +1,75 @@ +/* +** Copyright (c) 2024 Valve Corporation +** Copyright (c) 2024 LunarG, Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and associated documentation files (the "Software"), +** to deal in the Software without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Software, and to permit persons to whom the +** Software is furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +*/ + +#include "util/defines.h" +#include "util/logging.h" +#include "mark_injected_commands.h" + +GFXRECON_BEGIN_NAMESPACE(gfxrecon) +GFXRECON_BEGIN_NAMESPACE(decode) + +static void BeginEndInjectedCommandsNoop(void* data) +{ + GFXRECON_UNREFERENCED_PARAMETER(data); +} + +#ifdef GFXRECON_DEBUG_BUILD +static bool injecting_api_calls_g = false; +#endif + +static PFN_BeginInjectedCommands BeginInjectCommands_fp = BeginEndInjectedCommandsNoop; +static PFN_EndInjectedCommands EndInjectCommands_fp = BeginEndInjectedCommandsNoop; +static void* InjectCommandsData_ptr = nullptr; + +extern "C" void +SetInjectedCommandCallbacks(PFN_BeginInjectedCommands begin_fp, PFN_EndInjectedCommands end_fp, void* data) +{ + BeginInjectCommands_fp = begin_fp != nullptr ? begin_fp : BeginEndInjectedCommandsNoop; + EndInjectCommands_fp = end_fp != nullptr ? end_fp : BeginEndInjectedCommandsNoop; + InjectCommandsData_ptr = data; +} + +void BeginInjectedCommands() +{ +#ifdef GFXRECON_DEBUG_BUILD + // Nested BeginInjectedCommands/EndInjectedCommands + GFXRECON_ASSERT(!injecting_api_calls_g); + injecting_api_calls_g = true; +#endif + + BeginInjectCommands_fp(InjectCommandsData_ptr); +} + +void EndInjectedCommands() +{ +#ifdef GFXRECON_DEBUG_BUILD + // Nested BeginInjectedCommands/EndInjectedCommands + GFXRECON_ASSERT(injecting_api_calls_g); + injecting_api_calls_g = false; +#endif + + EndInjectCommands_fp(InjectCommandsData_ptr); +} + +GFXRECON_END_NAMESPACE(decode) +GFXRECON_END_NAMESPACE(gfxrecon) diff --git a/framework/decode/mark_injected_commands.h b/framework/decode/mark_injected_commands.h new file mode 100644 index 000000000..462b3ffe4 --- /dev/null +++ b/framework/decode/mark_injected_commands.h @@ -0,0 +1,48 @@ +/* +** Copyright (c) 2024 Valve Corporation +** Copyright (c) 2024 LunarG, Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and associated documentation files (the "Software"), +** to deal in the Software without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Software, and to permit persons to whom the +** Software is furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +*/ + +#include "util/defines.h" + +GFXRECON_BEGIN_NAMESPACE(gfxrecon) +GFXRECON_BEGIN_NAMESPACE(decode) + +using PFN_BeginInjectedCommands = void (*)(void*); +using PFN_EndInjectedCommands = void (*)(void*); +using PFN_SetInjectedCommandCallbacks = void (*)(PFN_BeginInjectedCommands, PFN_EndInjectedCommands, void*); + +// Interface for registering callbacks so that GFXReconstruct can notify an external library about +// generated API calls that are not included in the capture file. +// Intended usage: GFXR will call PFN_BeginInjectedCommands once before it starts issuing synthesized +// API calls, and PFN_EndInjectedCommands once it is finished. +// A void * pointer allows passing optional data that will be forwared into both callbacks. +// +// SetInjectedCommandCallbacks can be discovered through dlsym/GetProcAddress. +extern "C" void +SetInjectedCommandCallbacks(PFN_BeginInjectedCommands begin_fp, PFN_EndInjectedCommands end_fp, void* data); + +void BeginInjectedCommands(); + +void EndInjectedCommands(); + +GFXRECON_END_NAMESPACE(decode) +GFXRECON_END_NAMESPACE(gfxrecon) diff --git a/framework/decode/vulkan_replay_consumer_base.cpp b/framework/decode/vulkan_replay_consumer_base.cpp index 738982005..b2a47a6cf 100644 --- a/framework/decode/vulkan_replay_consumer_base.cpp +++ b/framework/decode/vulkan_replay_consumer_base.cpp @@ -49,6 +49,7 @@ #include "util/platform.h" #include "util/logging.h" #include "util/linear_hashmap.h" +#include "decode/mark_injected_commands.h" #include "spirv_reflect.h" @@ -2898,7 +2899,11 @@ void VulkanReplayConsumerBase::OverrideDestroyDevice( if (screenshot_handler_ != nullptr) { + decode::BeginInjectedCommands(); + screenshot_handler_->DestroyDeviceResources(device, GetDeviceTable(device)); + + decode::EndInjectedCommands(); } device_info->allocator->Destroy(); @@ -3603,6 +3608,8 @@ VkResult VulkanReplayConsumerBase::OverrideQueueSubmit(PFN_vkQueueSubmit fu if (screenshot_handler_ != nullptr) { + decode::BeginInjectedCommands(); + VulkanCommandBufferInfo* frame_boundary_command_buffer_info = nullptr; for (uint32_t i = 0; i < submitCount; ++i) { @@ -3638,6 +3645,8 @@ VkResult VulkanReplayConsumerBase::OverrideQueueSubmit(PFN_vkQueueSubmit fu } } } + + decode::EndInjectedCommands(); } return result; @@ -3778,6 +3787,8 @@ VkResult VulkanReplayConsumerBase::OverrideQueueSubmit2(PFN_vkQueueSubmit2 f // Check whether any of the submitted command buffers are frame boundaries. if (screenshot_handler_ != nullptr) { + decode::BeginInjectedCommands(); + bool is_frame_boundary = false; for (uint32_t i = 0; i < submitCount; ++i) { @@ -3802,6 +3813,8 @@ VkResult VulkanReplayConsumerBase::OverrideQueueSubmit2(PFN_vkQueueSubmit2 f } } } + + decode::EndInjectedCommands(); } return result; @@ -4070,6 +4083,8 @@ VkResult VulkanReplayConsumerBase::OverrideAllocateDescriptorSets( if ((original_result >= 0) && (result == VK_ERROR_OUT_OF_POOL_MEMORY)) { + decode::BeginInjectedCommands(); + // Handle case where replay runs out of descriptor pool memory when capture did not by creating a new // descriptor pool and attempting the allocation a second time. VkDescriptorPool new_pool = VK_NULL_HANDLE; @@ -4116,6 +4131,8 @@ VkResult VulkanReplayConsumerBase::OverrideAllocateDescriptorSets( result = func(device_info->handle, &modified_allocate_info, pDescriptorSets->GetHandlePointer()); } + + decode::EndInjectedCommands(); } // The information gathered here is only relevant to the dump resources feature @@ -6806,6 +6823,8 @@ VulkanReplayConsumerBase::OverrideQueuePresentKHR(PFN_vkQueuePresentKHR capture_image_indices_.clear(); swapchain_infos_.clear(); + decode::BeginInjectedCommands(); + if ((screenshot_handler_ != nullptr) && (screenshot_handler_->IsScreenshotFrame())) { auto meta_info = pPresentInfo->GetMetaStructPointer(); @@ -7054,6 +7073,8 @@ VulkanReplayConsumerBase::OverrideQueuePresentKHR(PFN_vkQueuePresentKHR GetDeviceTable(device)->DeviceWaitIdle(device); } + decode::EndInjectedCommands(); + // Only attempt to find imported or shadow semaphores if we know at least one around. if ((!have_imported_semaphores_) && (shadow_semaphores_.empty()) && (modified_present_info.swapchainCount != 0)) { @@ -7637,8 +7658,6 @@ VkResult VulkanReplayConsumerBase::OverrideCreateAccelerationStructureKHR( auto capture_id = (*pAccelerationStructureKHR->GetPointer()); auto replay_create_info = pCreateInfo->GetPointer(); VkDevice device = device_info->handle; - auto device_table = GetDeviceTable(device); - assert(device_table != nullptr); if (device_info->property_feature_info.feature_accelerationStructureCaptureReplay) { @@ -7657,13 +7676,11 @@ VkResult VulkanReplayConsumerBase::OverrideCreateAccelerationStructureKHR( capture_id); } - result = device_table->CreateAccelerationStructureKHR( - device, &modified_create_info, GetAllocationCallbacks(pAllocator), replay_accel_struct); + result = func(device, &modified_create_info, GetAllocationCallbacks(pAllocator), replay_accel_struct); } else { - result = device_table->CreateAccelerationStructureKHR( - device, replay_create_info, GetAllocationCallbacks(pAllocator), replay_accel_struct); + result = func(device, replay_create_info, GetAllocationCallbacks(pAllocator), replay_accel_struct); } return result; @@ -7822,7 +7839,6 @@ VkResult VulkanReplayConsumerBase::OverrideCreateRayTracingPipelinesKHR( VkResult result = VK_SUCCESS; VkDevice device = device_info->handle; - auto device_table = GetDeviceTable(device); const VkRayTracingPipelineCreateInfoKHR* in_pCreateInfos = pCreateInfos->GetPointer(); const VkAllocationCallbacks* in_pAllocator = GetAllocationCallbacks(pAllocator); VkPipeline* out_pPipelines = pPipelines->GetHandlePointer(); @@ -7916,13 +7932,13 @@ VkResult VulkanReplayConsumerBase::OverrideCreateRayTracingPipelinesKHR( created_pipelines = out_pPipelines; } - result = device_table->CreateRayTracingPipelinesKHR(device, - in_deferredOperation, - in_pipelineCache, - createInfoCount, - modified_create_infos.data(), - in_pAllocator, - created_pipelines); + result = func(device, + in_deferredOperation, + in_pipelineCache, + createInfoCount, + modified_create_infos.data(), + in_pAllocator, + created_pipelines); if ((result == VK_SUCCESS) || (result == VK_OPERATION_NOT_DEFERRED_KHR) || (result == VK_PIPELINE_COMPILE_REQUIRED_EXT)) @@ -7975,13 +7991,13 @@ VkResult VulkanReplayConsumerBase::OverrideCreateRayTracingPipelinesKHR( created_pipelines = out_pPipelines; } - result = device_table->CreateRayTracingPipelinesKHR(device, - in_deferredOperation, - in_pipelineCache, - createInfoCount, - in_pCreateInfos, - in_pAllocator, - created_pipelines); + result = func(device, + in_deferredOperation, + in_pipelineCache, + createInfoCount, + in_pCreateInfos, + in_pAllocator, + created_pipelines); if ((result == VK_SUCCESS) || (result == VK_OPERATION_NOT_DEFERRED_KHR) || (result == VK_PIPELINE_COMPILE_REQUIRED_EXT)) @@ -8685,6 +8701,8 @@ void VulkanReplayConsumerBase::OverrideFrameBoundaryANDROID(PFN_vkFrameBoundaryA if (screenshot_handler_ != nullptr) { + decode::BeginInjectedCommands(); + if (screenshot_handler_->IsScreenshotFrame() && image_info != nullptr) { const std::string filename_prefix = @@ -8721,6 +8739,8 @@ void VulkanReplayConsumerBase::OverrideFrameBoundaryANDROID(PFN_vkFrameBoundaryA } screenshot_handler_->EndFrame(); + + decode::EndInjectedCommands(); } func(device, semaphore, image); @@ -10088,8 +10108,9 @@ void VulkanReplayConsumerBase::OverrideDestroyShaderModule( } std::function()> VulkanReplayConsumerBase::AsyncCreateGraphicsPipelines( - const ApiCallInfo& call_info, + PFN_vkCreateGraphicsPipelines func, VkResult returnValue, + const ApiCallInfo& call_info, const VulkanDeviceInfo* device_info, const VulkanPipelineCacheInfo* pipeline_cache_info, uint32_t createInfoCount, @@ -10137,6 +10158,7 @@ std::function()> VulkanReplayConsumer auto task = [this, device_handle, pipeline_cache_handle, + func, returnValue, call_info, in_pAllocator, @@ -10153,8 +10175,7 @@ std::function()> VulkanReplayConsumer replaced_file_code = ReplaceShaders(createInfoCount, create_infos, pipelines.data()); } - auto device_table = GetDeviceTable(device_handle); - VkResult replay_result = device_table->CreateGraphicsPipelines( + VkResult replay_result = func( device_handle, pipeline_cache_handle, createInfoCount, create_infos, in_pAllocator, out_pipelines.data()); CheckResult("vkCreateGraphicsPipelines", returnValue, replay_result, call_info); @@ -10171,8 +10192,9 @@ std::function()> VulkanReplayConsumer } std::function()> VulkanReplayConsumerBase::AsyncCreateComputePipelines( - const ApiCallInfo& call_info, + PFN_vkCreateComputePipelines func, VkResult returnValue, + const ApiCallInfo& call_info, const VulkanDeviceInfo* device_info, const VulkanPipelineCacheInfo* pipeline_cache_info, uint32_t createInfoCount, @@ -10212,6 +10234,7 @@ std::function()> VulkanReplayConsumerBase::As auto task = [this, device_handle, pipeline_cache_handle, + func, returnValue, call_info, in_pAllocator, @@ -10220,8 +10243,7 @@ std::function()> VulkanReplayConsumerBase::As handle_deps = std::move(handle_deps)]() mutable -> handle_create_result_t { std::vector out_pipelines(createInfoCount); auto create_infos = reinterpret_cast(create_info_data.data()); - auto device_table = GetDeviceTable(device_handle); - VkResult replay_result = device_table->CreateComputePipelines( + VkResult replay_result = func( device_handle, pipeline_cache_handle, createInfoCount, create_infos, in_pAllocator, out_pipelines.data()); CheckResult("vkCreateComputePipelines", returnValue, replay_result, call_info); @@ -10238,8 +10260,9 @@ std::function()> VulkanReplayConsumerBase::As } std::function()> -VulkanReplayConsumerBase::AsyncCreateShadersEXT(const ApiCallInfo& call_info, +VulkanReplayConsumerBase::AsyncCreateShadersEXT(PFN_vkCreateShadersEXT func, VkResult returnValue, + const ApiCallInfo& call_info, const VulkanDeviceInfo* device_info, uint32_t createInfoCount, StructPointerDecoder* pCreateInfos, @@ -10272,6 +10295,7 @@ VulkanReplayConsumerBase::AsyncCreateShadersEXT(const ApiCallInfo& // define pipeline-creation task, assert object-lifetimes by copying/moving into closure auto task = [this, device_handle, + func, returnValue, call_info, in_pAllocator, @@ -10288,9 +10312,7 @@ VulkanReplayConsumerBase::AsyncCreateShadersEXT(const ApiCallInfo& replaced_file_code = ReplaceShaders(createInfoCount, create_infos, shaders.data()); } - auto device_table = GetDeviceTable(device_handle); - VkResult replay_result = device_table->CreateShadersEXT( - device_handle, createInfoCount, create_infos, in_pAllocator, out_shaders.data()); + VkResult replay_result = func(device_handle, createInfoCount, create_infos, in_pAllocator, out_shaders.data()); CheckResult("vkCreateShadersEXT", returnValue, replay_result, call_info); if (replay_result == VK_SUCCESS) diff --git a/framework/decode/vulkan_replay_consumer_base.h b/framework/decode/vulkan_replay_consumer_base.h index eca6c61c8..b94314ac9 100644 --- a/framework/decode/vulkan_replay_consumer_base.h +++ b/framework/decode/vulkan_replay_consumer_base.h @@ -1366,8 +1366,9 @@ class VulkanReplayConsumerBase : public VulkanConsumer const StructPointerDecoder* pAllocator); std::function()> - AsyncCreateGraphicsPipelines(const ApiCallInfo& call_info, + AsyncCreateGraphicsPipelines(PFN_vkCreateGraphicsPipelines func, VkResult returnValue, + const ApiCallInfo& call_info, const VulkanDeviceInfo* device_info, const VulkanPipelineCacheInfo* pipeline_cache_info, uint32_t createInfoCount, @@ -1376,8 +1377,9 @@ class VulkanReplayConsumerBase : public VulkanConsumer HandlePointerDecoder* pPipelines); std::function()> - AsyncCreateComputePipelines(const ApiCallInfo& call_info, + AsyncCreateComputePipelines(PFN_vkCreateComputePipelines func, VkResult returnValue, + const ApiCallInfo& call_info, const VulkanDeviceInfo* device_info, const VulkanPipelineCacheInfo* pipeline_cache_info, uint32_t createInfoCount, @@ -1386,8 +1388,9 @@ class VulkanReplayConsumerBase : public VulkanConsumer HandlePointerDecoder* pPipelines); std::function()> - AsyncCreateShadersEXT(const ApiCallInfo& call_info, + AsyncCreateShadersEXT(PFN_vkCreateShadersEXT func, VkResult returnValue, + const ApiCallInfo& call_info, const VulkanDeviceInfo* device_info, uint32_t createInfoCount, StructPointerDecoder* pCreateInfos, diff --git a/framework/decode/vulkan_virtual_swapchain.cpp b/framework/decode/vulkan_virtual_swapchain.cpp index 19430cf78..11bf37027 100644 --- a/framework/decode/vulkan_virtual_swapchain.cpp +++ b/framework/decode/vulkan_virtual_swapchain.cpp @@ -24,7 +24,8 @@ #include "decode/vulkan_resource_allocator.h" #include "decode/decoder_util.h" - +#include "decode/mark_injected_commands.h" +#include "vulkan/vulkan_core.h" #include GFXRECON_BEGIN_NAMESPACE(gfxrecon) @@ -152,8 +153,14 @@ void VulkanVirtualSwapchain::DestroySwapchainKHR(PFN_vkDestroySwapchainKHR f { if ((device_info != nullptr) && (swapchain_info != nullptr)) { + // CleanSwapchainResourceData() makes Vulkan API calls that are not in the capture file. + // Notify any layers by calling the provided pointer to their ReportReplayGeneratedVulkanCommands + decode::BeginInjectedCommands(); + CleanSwapchainResourceData(device_info, swapchain_info); + decode::EndInjectedCommands(); + VkDevice device = device_info->handle; VkSwapchainKHR swapchain = swapchain_info->handle; func(device, swapchain, allocator); @@ -625,8 +632,14 @@ VkResult VulkanVirtualSwapchain::GetSwapchainImagesKHR(VkResult return result; } - return CreateSwapchainResourceData( + // CreateSwapchainResourceData() makes Vulkan API calls that are not in the capture file. + // Notify any layers by calling the provided pointer to their ReportReplayGeneratedVulkanCommands + decode::BeginInjectedCommands(); + + result = CreateSwapchainResourceData( device_info, swapchain_info, capture_image_count, replay_image_count, images, false); + + decode::EndInjectedCommands(); } return result; @@ -713,6 +726,10 @@ VkResult VulkanVirtualSwapchain::QueuePresentKHR(VkResult return func(queue_info->handle, present_info); } + // Below Vulkan API calls are made that are not in the capture file. + // Notify any layers by calling the provided pointer to their ReportReplayGeneratedVulkanCommands + decode::BeginInjectedCommands(); + VkDevice device = queue_info->parent; VkQueue queue = queue_info->handle; uint32_t queue_family_index = queue_info->family_index; @@ -844,11 +861,14 @@ VkResult VulkanVirtualSwapchain::QueuePresentKHR(VkResult result = device_table_->ResetCommandBuffer(command_buffer, 0); if (result != VK_SUCCESS) { + decode::EndInjectedCommands(); + return result; } result = device_table_->BeginCommandBuffer(command_buffer, &begin_info); if (result != VK_SUCCESS) { + decode::EndInjectedCommands(); return result; } @@ -923,6 +943,8 @@ VkResult VulkanVirtualSwapchain::QueuePresentKHR(VkResult result = device_table_->EndCommandBuffer(command_buffer); if (result != VK_SUCCESS) { + decode::EndInjectedCommands(); + return result; } @@ -948,10 +970,14 @@ VkResult VulkanVirtualSwapchain::QueuePresentKHR(VkResult if (result != VK_SUCCESS) { + decode::EndInjectedCommands(); + return result; } } + decode::EndInjectedCommands(); + VkPresentInfoKHR modified_present_info = *present_info; modified_present_info.waitSemaphoreCount = static_cast(present_wait_semaphores.size()); modified_present_info.pWaitSemaphores = present_wait_semaphores.data(); diff --git a/framework/generated/generated_vulkan_replay_consumer.cpp b/framework/generated/generated_vulkan_replay_consumer.cpp index 4f776e73b..265c1f3e7 100644 --- a/framework/generated/generated_vulkan_replay_consumer.cpp +++ b/framework/generated/generated_vulkan_replay_consumer.cpp @@ -987,7 +987,7 @@ void VulkanReplayConsumer::Process_vkCreateGraphicsPipelines( if (UseAsyncOperations()) { - auto task = AsyncCreateGraphicsPipelines(call_info, returnValue, in_device, in_pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); + auto task = AsyncCreateGraphicsPipelines(GetDeviceTable(in_device->handle)->CreateGraphicsPipelines, returnValue, call_info, in_device, in_pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); if(task) { AddHandlesAsync(device, pPipelines->GetPointer(), pPipelines->GetLength(), std::move(handle_info), &VulkanObjectInfoTable::AddVkPipelineInfo, std::move(task)); @@ -1021,7 +1021,7 @@ void VulkanReplayConsumer::Process_vkCreateComputePipelines( if (UseAsyncOperations()) { - auto task = AsyncCreateComputePipelines(call_info, returnValue, in_device, in_pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); + auto task = AsyncCreateComputePipelines(GetDeviceTable(in_device->handle)->CreateComputePipelines, returnValue, call_info, in_device, in_pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); if(task) { AddHandlesAsync(device, pPipelines->GetPointer(), pPipelines->GetLength(), std::move(handle_info), &VulkanObjectInfoTable::AddVkPipelineInfo, std::move(task)); @@ -10116,7 +10116,7 @@ void VulkanReplayConsumer::Process_vkCreateShadersEXT( if (UseAsyncOperations()) { - auto task = AsyncCreateShadersEXT(call_info, returnValue, in_device, createInfoCount, pCreateInfos, pAllocator, pShaders); + auto task = AsyncCreateShadersEXT(GetDeviceTable(in_device->handle)->CreateShadersEXT, returnValue, call_info, in_device, createInfoCount, pCreateInfos, pAllocator, pShaders); if(task) { AddHandlesAsync(device, pShaders->GetPointer(), pShaders->GetLength(), std::move(handle_info), &VulkanObjectInfoTable::AddVkShaderEXTInfo, std::move(task)); diff --git a/framework/generated/vulkan_generators/vulkan_replay_consumer_body_generator.py b/framework/generated/vulkan_generators/vulkan_replay_consumer_body_generator.py index f4a21b158..62cc3ed8b 100644 --- a/framework/generated/vulkan_generators/vulkan_replay_consumer_body_generator.py +++ b/framework/generated/vulkan_generators/vulkan_replay_consumer_body_generator.py @@ -341,7 +341,7 @@ def make_consumer_func_body(self, return_type, name, values): if is_async: body += ' if (UseAsyncOperations())\n' body += ' {\n' - body += ' auto task = {}(call_info, returnValue, {});\n'.format(self.REPLAY_ASYNC_OVERRIDES[name], arglist) + body += ' auto task = {}({}, returnValue, call_info, {});\n'.format(self.REPLAY_ASYNC_OVERRIDES[name], dispatchfunc, arglist) body += ' if(task)\n' body += ' {\n' body += ' {}\n'.format(postexpr[0]) diff --git a/tools/replay/CMakeLists.txt b/tools/replay/CMakeLists.txt index 01430b1c5..58ab28e34 100644 --- a/tools/replay/CMakeLists.txt +++ b/tools/replay/CMakeLists.txt @@ -51,6 +51,8 @@ target_link_libraries(gfxrecon-replay $<$:dxgi.lib> $<$:${DXC_LIBRARY_PATH}>) +target_link_options(gfxrecon-replay PUBLIC "-rdynamic") + if (MSVC) # Force inclusion of "gfxrecon_disable_popup_result" variable in linking. # On 32-bit windows, MSVC prefixes symbols with "_" but on 64-bit windows it doesn't. diff --git a/tools/replay/android_main.cpp b/tools/replay/android_main.cpp index 1abf506ea..d95ed25bf 100644 --- a/tools/replay/android_main.cpp +++ b/tools/replay/android_main.cpp @@ -59,6 +59,21 @@ void ProcessAppCmd(struct android_app* app, int32_t cmd); int32_t ProcessInputEvent(struct android_app* app, AInputEvent* event); void DestroyActivity(struct android_app* app); +static std::unique_ptr file_processor; + +extern "C" +{ + uint64_t MainGetCurrentBlockIndex() + { + return file_processor->GetCurrentBlockIndex(); + } + + bool MainGetLoadingTrimmedState() + { + return file_processor->GetLoadingTrimmedState(); + } +} + void android_main(struct android_app* app) { gfxrecon::util::Log::Init(); @@ -102,10 +117,9 @@ void android_main(struct android_app* app) try { - std::unique_ptr file_processor = - arg_parser.IsOptionSet(kPreloadMeasurementRangeOption) - ? std::make_unique() - : std::make_unique(); + file_processor = arg_parser.IsOptionSet(kPreloadMeasurementRangeOption) + ? std::make_unique() + : std::make_unique(); if (!file_processor->Initialize(filename)) {