diff --git a/framework/decode/dx_replay_options.h b/framework/decode/dx_replay_options.h index 43bd47b58a..af40732ff6 100644 --- a/framework/decode/dx_replay_options.h +++ b/framework/decode/dx_replay_options.h @@ -56,13 +56,7 @@ struct DxReplayOptions : public ReplayOptions bool override_object_names{ false }; bool enable_dump_resources{ false }; DumpResourcesTarget dump_resources_target{}; - - util::ScreenshotFormat screenshot_format{ util::ScreenshotFormat::kBmp }; - std::vector screenshot_ranges; - std::string screenshot_dir; - std::string screenshot_file_prefix{ kDefaultScreenshotFilePrefix }; - std::string replace_dir; - int32_t memory_usage{ kDefaultBatchingMemoryUsage }; + int32_t memory_usage{ kDefaultBatchingMemoryUsage }; }; GFXRECON_END_NAMESPACE(decode) diff --git a/framework/decode/replay_options.h b/framework/decode/replay_options.h index 1316f7360e..cfdf816b9e 100644 --- a/framework/decode/replay_options.h +++ b/framework/decode/replay_options.h @@ -41,27 +41,34 @@ struct ScreenshotRange struct ReplayOptions { - bool enable_validation_layer{ false }; - bool sync_queue_submissions{ false }; - bool enable_debug_device_lost{ false }; - bool create_dummy_allocations{ false }; - bool omit_null_hardware_buffers{ false }; - bool quit_after_measurement_frame_range{ false }; - bool flush_measurement_frame_range{ false }; - bool flush_inside_measurement_range{ false }; - bool force_windowed{ false }; - uint32_t windowed_width{ 0 }; - uint32_t windowed_height{ 0 }; - bool force_windowed_origin{ false }; - int32_t window_topleft_x{ 0 }; - int32_t window_topleft_y{ 0 }; - int32_t override_gpu_index{ -1 }; - std::string capture_filename; - bool enable_print_block_info{ false }; - int64_t block_index_from{ -1 }; - int64_t block_index_to{ -1 }; - int32_t num_pipeline_creation_jobs{ 0 }; - std::string asset_file_path; + bool enable_validation_layer{ false }; + bool sync_queue_submissions{ false }; + bool enable_debug_device_lost{ false }; + bool create_dummy_allocations{ false }; + bool omit_null_hardware_buffers{ false }; + bool quit_after_measurement_frame_range{ false }; + bool flush_measurement_frame_range{ false }; + bool flush_inside_measurement_range{ false }; + bool force_windowed{ false }; + uint32_t windowed_width{ 0 }; + uint32_t windowed_height{ 0 }; + bool force_windowed_origin{ false }; + int32_t window_topleft_x{ 0 }; + int32_t window_topleft_y{ 0 }; + int32_t override_gpu_index{ -1 }; + std::string capture_filename; + bool enable_print_block_info{ false }; + int64_t block_index_from{ -1 }; + int64_t block_index_to{ -1 }; + bool skip_failed_allocations{ false }; + bool remove_unsupported_features{ false }; + util::ScreenshotFormat screenshot_format{ util::ScreenshotFormat::kBmp }; + std::vector screenshot_ranges; + std::string screenshot_dir; + std::string screenshot_file_prefix{ kDefaultScreenshotFilePrefix }; + uint32_t screenshot_width, screenshot_height; + int32_t num_pipeline_creation_jobs{ 0 }; + std::string asset_file_path; }; GFXRECON_END_NAMESPACE(decode) diff --git a/framework/decode/struct_pointer_decoder.h b/framework/decode/struct_pointer_decoder.h index 8d8d51d021..b54d15e578 100644 --- a/framework/decode/struct_pointer_decoder.h +++ b/framework/decode/struct_pointer_decoder.h @@ -39,10 +39,35 @@ #include #include +#include +#include GFXRECON_BEGIN_NAMESPACE(gfxrecon) GFXRECON_BEGIN_NAMESPACE(decode) +template +struct DecoderHasOutputAllocator : std::false_type +{}; + +template +struct DecoderHasOutputAllocator().AllocateOutputData(size_t(1)))>> + : std::true_type +{}; + +template +std::enable_if_t::value, typename T::struct_type*> +StructPointerOutputDataAllocator(T*, size_t len) +{ + return DecodeAllocator::Allocate(len); +} + +template +std::enable_if_t::value, typename T::struct_type*> +StructPointerOutputDataAllocator(T* decoded_value, size_t len) +{ + return decoded_value->AllocateOutputData(len); +} + template class StructPointerDecoder : public PointerDecoderBase { @@ -68,12 +93,13 @@ class StructPointerDecoder : public PointerDecoderBase typename T::struct_type* AllocateOutputData(size_t len) { output_len_ = len; - output_data_ = DecodeAllocator::Allocate(len); + output_data_ = StructPointerOutputDataAllocator(decoded_structs_, len); return output_data_; } typename T::struct_type* AllocateOutputData(size_t len, const typename T::struct_type& init) { + assert(!DecoderHasOutputAllocator::value); output_len_ = len; output_data_ = DecodeAllocator::Allocate(len); @@ -222,7 +248,10 @@ class StructPointerDecoder : public PointerDecoderBase typename T::struct_type* inner_struct_memory = DecodeAllocator::Allocate(inner_lens_[i]); - T* inner_decoded_structs = DecodeAllocator::Allocate(inner_lens_[i]); + // TODO: We initialize == true because the nexe field isn't always cleared on kIsNull in the lower + // level decoders. If this is a performance bottleneck, can clean up the lower decoders to + // initialize all fields. + T* inner_decoded_structs = DecodeAllocator::Allocate(inner_lens_[i], true); for (size_t j = 0; j < inner_lens_[i]; ++j) { diff --git a/framework/decode/vulkan_object_info.h b/framework/decode/vulkan_object_info.h index 4c1cf236c3..605f3d5231 100644 --- a/framework/decode/vulkan_object_info.h +++ b/framework/decode/vulkan_object_info.h @@ -288,6 +288,16 @@ struct VulkanPhysicalDeviceInfo : public VulkanObjectInfo // Closest matching replay device. VulkanReplayDeviceInfo* replay_device_info{ nullptr }; + + // Because Vulkan captures unwrapped handles, and layered APIs (like OpenXR) + // capture wrapped handles, during replay two HandleId values will reference + // the same VkPhysical device. The vulkan_alias is the handleId as known by + // the vulkan_consumers, which will be created/updated, etc, by all Vulkan replay + // calls, s.t. the information known by the vulkan_consumer need not be duplicated. + // Operations on this, will use the vulkan_alias as the effective HandleId when set. + + // When Non-null, the GetVkObject will recur on the alias Id + format::HandleId vulkan_alias{ format::kNullHandleId }; }; struct VulkanDeviceInfo : public VulkanObjectInfo diff --git a/framework/decode/vulkan_object_info_table_base.h b/framework/decode/vulkan_object_info_table_base.h index 07cfb5ae57..0f40ddf9bd 100644 --- a/framework/decode/vulkan_object_info_table_base.h +++ b/framework/decode/vulkan_object_info_table_base.h @@ -32,6 +32,7 @@ #include #include +#include #include GFXRECON_BEGIN_NAMESPACE(gfxrecon) @@ -49,6 +50,72 @@ struct has_handle_future template inline constexpr bool has_handle_future_v = has_handle_future::value; +// NOTE: There's nothing VulkanSpecific in these utilities +// TODO: Find a better home for these + +// Utility functors to implement const and non-const versions of getters in a common impl +template +using ConstCorrectMappedTypePtr = decltype(&(std::declval().begin()->second)); + +struct ObjectInfoGetterBase +{ + template + MappedTypePtr GetObjectInfoImpl(format::HandleId id, Map* map) + { + assert(map != nullptr); + + MappedTypePtr object_info = nullptr; + + if (id != 0) + { + const auto entry = map->find(id); + + if (entry != map->end()) + { + object_info = &entry->second; + } + } + + return object_info; + } + template + MappedTypePtr GetAliasingObjectInfoImpl(format::HandleId id, Map* map) + { + MappedTypePtr object_info = GetObjectInfoImpl(id, map); + if (object_info && (object_info->vulkan_alias != format::kNullHandleId)) + { + object_info = GetObjectInfoImpl(object_info->vulkan_alias, map); + // Note: if id has an alias and the alias is valid, the alias must not alias. Aliasing is single level. + assert(!object_info || (object_info->vulkan_alias == format::kNullHandleId)); + } + return object_info; + } +}; + +// Because of " explicit specialization in non-namespace scope" these must be implemented outside the class below +template +struct ObjectInfoGetter : public ObjectInfoGetterBase +{ + template > + MappedTypePtr operator()(format::HandleId id, Map* map) + { + return GetObjectInfoImpl(id, map); + } +}; + +// Specialize to handle physical device aliasing. See comments for VulkanPhysicalDeviceInfo::vulkan_alias +// Note: could do SFINAE a "has member" check on vulkan_alias, but as only physical device needs aliasing support at +// this time, it's simpler just to specialize for VulkanPhysicalDeviceInfo +template <> +struct ObjectInfoGetter : public ObjectInfoGetterBase +{ + template > + MappedTypePtr operator()(format::HandleId id, Map* map) + { + return GetAliasingObjectInfoImpl(id, map); + } +}; + class VulkanObjectInfoTableBase { protected: @@ -132,41 +199,13 @@ class VulkanObjectInfoTableBase template const T* GetVkObjectInfo(format::HandleId id, const std::unordered_map* map) const { - assert(map != nullptr); - - const T* object_info = nullptr; - - if (id != 0) - { - const auto entry = map->find(id); - - if (entry != map->end()) - { - object_info = &entry->second; - } - } - - return object_info; + return ObjectInfoGetter()(id, map); } template T* GetVkObjectInfo(format::HandleId id, std::unordered_map* map) { - assert(map != nullptr); - - T* object_info = nullptr; - - if (id != 0) - { - auto entry = map->find(id); - - if (entry != map->end()) - { - object_info = &entry->second; - } - } - - return object_info; + return ObjectInfoGetter()(id, map); } }; diff --git a/framework/decode/vulkan_replay_consumer_base.cpp b/framework/decode/vulkan_replay_consumer_base.cpp index c86fe5f5c5..d01a785efd 100644 --- a/framework/decode/vulkan_replay_consumer_base.cpp +++ b/framework/decode/vulkan_replay_consumer_base.cpp @@ -1270,6 +1270,41 @@ void VulkanReplayConsumerBase::CheckReplayDeviceInfo(VulkanPhysicalDeviceInfo* p } } +// Needed to support physical device aliasing. See comments for VulkanPhysicalDeviceInfo::vulkan_alias +void VulkanReplayConsumerBase::SetPhysicalDeviceAlias(format::HandleId instance, + VulkanPhysicalDeviceInfo& replay_physical_device) +{ + if ((replay_physical_device.capture_id == format::kNullHandleId) || + (replay_physical_device.handle == VK_NULL_HANDLE)) + { + return; + } + + const format::HandleId match_id = replay_physical_device.capture_id; + const VkPhysicalDevice match_handle = replay_physical_device.handle; + + auto instance_info = object_info_table_->GetVkInstanceInfo(instance); + assert(instance_info); + + for (const format::HandleId capture_device : instance_info->capture_devices) + { + const VulkanPhysicalDeviceInfo* physical_device_info = + GetObjectInfoTable().GetVkPhysicalDeviceInfo(capture_device); + if (!physical_device_info || (physical_device_info->vulkan_alias != format::kNullHandleId)) + { + continue; // only single depth aliasing + } + + const format::HandleId& capture_id = physical_device_info->capture_id; + const VkPhysicalDevice& handle = physical_device_info->handle; + if ((handle == match_handle) && (capture_id != match_id)) + { + replay_physical_device.vulkan_alias = capture_id; + break; + } + } +} + void VulkanReplayConsumerBase::SetPhysicalDeviceInstanceInfo(VulkanInstanceInfo* instance_info, VulkanPhysicalDeviceInfo* physical_device_info, VkPhysicalDevice replay_device) @@ -1572,6 +1607,13 @@ bool VulkanReplayConsumerBase::GetOverrideDeviceGroup(VulkanInstanceInfo* return true; } +void VulkanReplayConsumerBase::GetMatchingDevice(VulkanPhysicalDeviceInfo* physical_device_info) +{ + VulkanInstanceInfo* instance_info = object_info_table_->GetVkInstanceInfo(physical_device_info->parent_id); + assert(instance_info); + GetMatchingDevice(instance_info, physical_device_info); +} + void VulkanReplayConsumerBase::GetMatchingDevice(VulkanInstanceInfo* instance_info, VulkanPhysicalDeviceInfo* physical_device_info) { @@ -2334,29 +2376,21 @@ bool VulkanReplayConsumerBase::CheckPNextChainForFrameBoundary(const VulkanDevic return true; } -VkResult -VulkanReplayConsumerBase::OverrideCreateInstance(VkResult original_result, - const StructPointerDecoder* pCreateInfo, - const StructPointerDecoder* pAllocator, - HandlePointerDecoder* pInstance) +void VulkanReplayConsumerBase::ModifyCreateInstanceInfo( + const StructPointerDecoder* pCreateInfo, CreateInstanceInfoState& create_state) { - GFXRECON_UNREFERENCED_PARAMETER(original_result); - - assert((pInstance != nullptr) && !pInstance->IsNull() && (pInstance->GetHandlePointer() != nullptr) && - (pCreateInfo != nullptr) && (pCreateInfo->GetPointer() != nullptr) && - (pInstance->GetHandlePointer() != nullptr)); const VkInstanceCreateInfo* replay_create_info = pCreateInfo->GetPointer(); - VkInstance* replay_instance = pInstance->GetHandlePointer(); if (loader_handle_ == nullptr) { InitializeLoader(); } - std::vector modified_layers; - std::vector modified_extensions; - VkInstanceCreateInfo modified_create_info = (*replay_create_info); + std::vector& modified_layers = create_state.modified_layers; + std::vector& modified_extensions = create_state.modified_extensions; + VkInstanceCreateInfo& modified_create_info = create_state.modified_create_info; + modified_create_info = *replay_create_info; // If VkDebugUtilsMessengerCreateInfoEXT or VkDebugReportCallbackCreateInfoEXT are in the pNext chain, update the // callback pointers. @@ -2534,63 +2568,77 @@ VulkanReplayConsumerBase::OverrideCreateInstance(VkResult original_result, modified_create_info.enabledLayerCount = static_cast(modified_layers.size()); modified_create_info.ppEnabledLayerNames = modified_layers.data(); } +} - VkResult result = create_instance_proc_(&modified_create_info, GetAllocationCallbacks(pAllocator), replay_instance); +void VulkanReplayConsumerBase::PostCreateInstanceUpdateState(const VkInstance replay_instance, + const VkInstanceCreateInfo& modified_create_info, + VulkanInstanceInfo& instance_info) +{ + AddInstanceTable(replay_instance); - if ((replay_instance != nullptr) && (result == VK_SUCCESS)) + if (modified_create_info.pApplicationInfo != nullptr) { - AddInstanceTable(*replay_instance); - - if (modified_create_info.pApplicationInfo != nullptr) - { - auto instance_info = reinterpret_cast(pInstance->GetConsumerData(0)); - assert(instance_info != nullptr); - - instance_info->api_version = modified_create_info.pApplicationInfo->apiVersion; - instance_info->enabled_extensions.assign(modified_create_info.ppEnabledExtensionNames, - modified_create_info.ppEnabledExtensionNames + - modified_create_info.enabledExtensionCount); - } + instance_info.api_version = modified_create_info.pApplicationInfo->apiVersion; + instance_info.enabled_extensions.assign(modified_create_info.ppEnabledExtensionNames, + modified_create_info.ppEnabledExtensionNames + + modified_create_info.enabledExtensionCount); } - - return result; } VkResult -VulkanReplayConsumerBase::OverrideCreateDevice(VkResult original_result, - VulkanPhysicalDeviceInfo* physical_device_info, - const StructPointerDecoder* pCreateInfo, - const StructPointerDecoder* pAllocator, - HandlePointerDecoder* pDevice) +VulkanReplayConsumerBase::OverrideCreateInstance(VkResult original_result, + const StructPointerDecoder* pCreateInfo, + const StructPointerDecoder* pAllocator, + HandlePointerDecoder* pInstance) { GFXRECON_UNREFERENCED_PARAMETER(original_result); - assert((physical_device_info != nullptr) && (pDevice != nullptr) && !pDevice->IsNull() && - (pDevice->GetHandlePointer() != nullptr) && (pCreateInfo != nullptr)); + assert((pInstance != nullptr) && !pInstance->IsNull() && (pInstance->GetHandlePointer() != nullptr) && + (pCreateInfo != nullptr) && (pCreateInfo->GetPointer() != nullptr) && + (pInstance->GetHandlePointer() != nullptr)); - SelectPhysicalDevice(physical_device_info); + // Update the create info to reflect the expectations/limitations of the replaying system (and of GFXR) + // Note: create_state is passed into the Modify call to allow the modified_create_info to reference + // addresses of create_state members which a return value doesn't appear to preserve + CreateInstanceInfoState create_state; + ModifyCreateInstanceInfo(pCreateInfo, create_state); - VkPhysicalDevice physical_device = physical_device_info->handle; - PFN_vkGetDeviceProcAddr get_device_proc_addr = GetDeviceAddrProc(physical_device); - PFN_vkCreateDevice create_device_proc = GetCreateDeviceProc(physical_device); + VkInstance* replay_instance = pInstance->GetHandlePointer(); + assert(replay_instance); + *replay_instance = VK_NULL_HANDLE; - if ((get_device_proc_addr == nullptr) || (create_device_proc == nullptr)) + VkResult result = + create_instance_proc_(&create_state.modified_create_info, GetAllocationCallbacks(pAllocator), replay_instance); + + if ((*replay_instance != VK_NULL_HANDLE) && (result == VK_SUCCESS)) { - return VK_ERROR_INITIALIZATION_FAILED; + auto instance_info = reinterpret_cast(pInstance->GetConsumerData(0)); + assert(instance_info); + PostCreateInstanceUpdateState(*replay_instance, create_state.modified_create_info, *instance_info); } - VkResult result = VK_ERROR_INITIALIZATION_FAILED; + return result; +} + +void VulkanReplayConsumerBase::ModifyCreateDeviceInfo( + VulkanPhysicalDeviceInfo* physical_device_info, + const StructPointerDecoder* pCreateInfo, + CreateDeviceInfoState& create_state) +{ + const VkPhysicalDevice physical_device = physical_device_info->handle; + auto instance_table = GetInstanceTable(physical_device); assert(instance_table != nullptr); auto replay_create_info = pCreateInfo->GetPointer(); - auto replay_device = pDevice->GetHandlePointer(); assert(replay_create_info != nullptr); - VkDeviceCreateInfo modified_create_info = (*replay_create_info); - std::vector modified_extensions; + VkDeviceCreateInfo& modified_create_info = create_state.modified_create_info; + std::vector& modified_extensions = create_state.modified_extensions; + std::vector& replay_device_group = create_state.replay_device_group; + VkDeviceGroupDeviceCreateInfo& modified_device_group_create_info = create_state.modified_device_group_create_info; - // Attempt to recreate capture device group with replay device group + modified_create_info = (*replay_create_info); // Attempt to recreate capture device group with replay device group const auto decoded_capture_create_info = pCreateInfo->GetMetaStructPointer(); std::vector capture_device_group; @@ -2605,8 +2653,6 @@ VulkanReplayConsumerBase::OverrideCreateDevice(VkResult origina std::copy(handle_ids, handle_ids + len, std::back_inserter(capture_device_group)); } - VkDeviceGroupDeviceCreateInfo modified_device_group_create_info = {}; - std::vector replay_device_group; const VkBaseInStructure* replay_previous_next = reinterpret_cast(&modified_create_info); const VkBaseInStructure* replay_next = reinterpret_cast(modified_create_info.pNext); @@ -2643,7 +2689,7 @@ VulkanReplayConsumerBase::OverrideCreateDevice(VkResult origina } // Enable extensions used for loading resources during initial state setup for trimmed files. - std::vector trim_extensions; + std::vector& trim_extensions = create_state.trim_extensions; if (loading_trim_state_ && CheckTrimDeviceExtensions(physical_device, &trim_extensions)) { for (const auto& extension : trim_extensions) @@ -2705,8 +2751,7 @@ VulkanReplayConsumerBase::OverrideCreateDevice(VkResult origina modified_create_info.ppEnabledExtensionNames = modified_extensions.data(); // Enable necessary features - graphics::VulkanDeviceUtil device_util; - graphics::VulkanDevicePropertyFeatureInfo property_feature_info = device_util.EnableRequiredPhysicalDeviceFeatures( + create_state.property_feature_info = create_state.device_util.EnableRequiredPhysicalDeviceFeatures( physical_device_info->parent_api_version, instance_table, physical_device, &modified_create_info); // Abort on/Remove unsupported features @@ -2716,23 +2761,24 @@ VulkanReplayConsumerBase::OverrideCreateDevice(VkResult origina modified_create_info.pNext, modified_create_info.pEnabledFeatures, options_.remove_unsupported_features); +} - // Forward device creation to next layer/driver - result = - create_device_proc(physical_device, &modified_create_info, GetAllocationCallbacks(pAllocator), replay_device); - - if ((replay_device == nullptr) || (result != VK_SUCCESS)) +VkResult VulkanReplayConsumerBase::PostCreateDeviceUpdateState(VulkanPhysicalDeviceInfo* physical_device_info, + const VkDevice replay_device, + CreateDeviceInfoState& create_state, + VulkanDeviceInfo* device_info) +{ + VkPhysicalDevice physical_device = physical_device_info->handle; + PFN_vkGetDeviceProcAddr get_device_proc_addr = GetDeviceAddrProc(physical_device); + if (get_device_proc_addr == nullptr) { - return result; + return VK_ERROR_INITIALIZATION_FAILED; } + AddDeviceTable(replay_device, get_device_proc_addr); - AddDeviceTable(*replay_device, get_device_proc_addr); - - auto device_info = reinterpret_cast(pDevice->GetConsumerData(0)); assert(device_info != nullptr); - - device_info->replay_device_group = std::move(replay_device_group); - device_info->extensions = std::move(trim_extensions); + device_info->replay_device_group = std::move(create_state.replay_device_group); + device_info->extensions = std::move(create_state.trim_extensions); device_info->parent = physical_device; // Create the memory allocator for the selected physical device. @@ -2751,32 +2797,32 @@ VulkanReplayConsumerBase::OverrideCreateDevice(VkResult origina auto allocator = options_.create_resource_allocator(); - std::vector enabled_extensions(modified_create_info.ppEnabledExtensionNames, - modified_create_info.ppEnabledExtensionNames + - modified_create_info.enabledExtensionCount); - InitializeResourceAllocator(physical_device_info, *replay_device, enabled_extensions, allocator); + std::vector enabled_extensions(create_state.modified_create_info.ppEnabledExtensionNames, + create_state.modified_create_info.ppEnabledExtensionNames + + create_state.modified_create_info.enabledExtensionCount); + InitializeResourceAllocator(physical_device_info, replay_device, enabled_extensions, allocator); device_info->allocator = std::unique_ptr(allocator); // Track state of physical device properties and features at device creation - device_info->property_feature_info = property_feature_info; + device_info->property_feature_info = create_state.property_feature_info; // Keep track of what queue families this device is planning on using. This information is // very important if we end up using the VulkanVirtualSwapchain path. auto max = [](uint32_t current_max, const VkDeviceQueueCreateInfo& dqci) { return std::max(current_max, dqci.queueFamilyIndex); }; - uint32_t max_queue_family = - std::accumulate(modified_create_info.pQueueCreateInfos, - modified_create_info.pQueueCreateInfos + modified_create_info.queueCreateInfoCount, - 0, - max); + uint32_t max_queue_family = std::accumulate(create_state.modified_create_info.pQueueCreateInfos, + create_state.modified_create_info.pQueueCreateInfos + + create_state.modified_create_info.queueCreateInfoCount, + 0, + max); device_info->queue_family_index_enabled.clear(); device_info->queue_family_index_enabled.resize(max_queue_family + 1, false); - for (uint32_t q = 0; q < modified_create_info.queueCreateInfoCount; ++q) + for (uint32_t q = 0; q < create_state.modified_create_info.queueCreateInfoCount; ++q) { - const VkDeviceQueueCreateInfo* queue_create_info = &modified_create_info.pQueueCreateInfos[q]; + const VkDeviceQueueCreateInfo* queue_create_info = &create_state.modified_create_info.pQueueCreateInfos[q]; assert(device_info->queue_family_creation_flags.find(queue_create_info->queueFamilyIndex) == device_info->queue_family_creation_flags.end()); device_info->queue_family_creation_flags[queue_create_info->queueFamilyIndex] = queue_create_info->flags; @@ -2784,8 +2830,57 @@ VulkanReplayConsumerBase::OverrideCreateDevice(VkResult origina } // Restore modified property/feature create info values to the original application values - device_util.RestoreModifiedPhysicalDeviceFeatures(); + create_state.device_util.RestoreModifiedPhysicalDeviceFeatures(); + + return VK_SUCCESS; +} + +VkResult +VulkanReplayConsumerBase::OverrideCreateDevice(VkResult original_result, + VulkanPhysicalDeviceInfo* physical_device_info, + const StructPointerDecoder* pCreateInfo, + const StructPointerDecoder* pAllocator, + HandlePointerDecoder* pDevice) +{ + GFXRECON_UNREFERENCED_PARAMETER(original_result); + + assert((physical_device_info != nullptr) && (pDevice != nullptr) && !pDevice->IsNull() && + (pDevice->GetHandlePointer() != nullptr) && (pCreateInfo != nullptr)); + + // NOTE: This must be first as it *sets* the physical_device_info->handle to point to the replay physical device + SelectPhysicalDevice(physical_device_info); + + VkPhysicalDevice physical_device = physical_device_info->handle; + + PFN_vkCreateDevice create_device_proc = GetCreateDeviceProc(physical_device); + + if (create_device_proc == nullptr) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + + // Update the create info to reflect the expectations/limitations of the replaying system (and of GFXR) + // Note: create_state is passed into the Modify call to allow the modified_create_info to reference + // addresses of create_state members which a return value doesn't appear to preserve + CreateDeviceInfoState create_state; + ModifyCreateDeviceInfo(physical_device_info, pCreateInfo, create_state); + + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + auto replay_device = pDevice->GetHandlePointer(); + assert(replay_device); + + // Forward device creation to next layer/driver + result = create_device_proc( + physical_device, &create_state.modified_create_info, GetAllocationCallbacks(pAllocator), replay_device); + + if ((replay_device == nullptr) || (result != VK_SUCCESS)) + { + return result; + } + VulkanDeviceInfo* device_info = reinterpret_cast(pDevice->GetConsumerData(0)); + assert(device_info); + result = PostCreateDeviceUpdateState(physical_device_info, *replay_device, create_state, device_info); return result; } @@ -5699,7 +5794,7 @@ VkResult VulkanReplayConsumerBase::OverrideCreateShaderModule( (pShaderModule != nullptr) && !pShaderModule->IsNull()); auto original_info = pCreateInfo->GetPointer(); - if (original_result < 0 || options_.replace_dir.empty()) + if (original_result < 0 || options_.replace_shader_dir.empty()) { VkResult vk_res = func( device_info->handle, original_info, GetAllocationCallbacks(pAllocator), pShaderModule->GetHandlePointer()); @@ -5738,7 +5833,7 @@ VkResult VulkanReplayConsumerBase::OverrideCreateShaderModule( const size_t orig_size = original_info->codeSize; uint64_t handle_id = *pShaderModule->GetPointer(); std::string file_name = "sh" + std::to_string(handle_id); - std::string file_path = util::filepath::Join(options_.replace_dir, file_name); + std::string file_path = util::filepath::Join(options_.replace_shader_dir, file_name); FILE* fp = nullptr; int32_t result = util::platform::FileOpen(&fp, file_path.c_str(), "rb"); @@ -9651,7 +9746,7 @@ void VulkanReplayConsumerBase::OverrideUpdateDescriptorSets( uint64_t handle_id = pipelines[i]; std::string file_name = "sh" + std::to_string(handle_id) + "_" + std::to_string(stage_create_info.stage); - std::string file_path = util::filepath::Join(options_.replace_dir, file_name); + std::string file_path = util::filepath::Join(options_.replace_shader_dir, file_name); FILE* fp = nullptr; int32_t result = util::platform::FileOpen(&fp, file_path.c_str(), "rb"); @@ -9699,7 +9794,7 @@ VkResult VulkanReplayConsumerBase::OverrideCreateGraphicsPipelines( std::vector> replaced_file_code; auto* maybe_replaced_create_infos = in_p_create_infos; - if (original_result >= 0 && !options_.replace_dir.empty()) + if (original_result >= 0 && !options_.replace_shader_dir.empty()) { uint32_t num_bytes = graphics::vulkan_struct_deep_copy(in_p_create_infos, create_info_count, nullptr); create_info_data.resize(num_bytes); @@ -9790,7 +9885,7 @@ VkResult VulkanReplayConsumerBase::OverrideCreateComputePipelines( size_t orig_size = create_info->codeSize; uint64_t handle_id = shaders[i]; std::string file_name = "sh" + std::to_string(handle_id); - std::string file_path = util::filepath::Join(options_.replace_dir, file_name); + std::string file_path = util::filepath::Join(options_.replace_shader_dir, file_name); FILE* fp = nullptr; int32_t result = util::platform::FileOpen(&fp, file_path.c_str(), "rb"); @@ -9832,7 +9927,7 @@ VkResult VulkanReplayConsumerBase::OverrideCreateShadersEXT( std::vector> replaced_file_code; auto* maybe_replaced_create_infos = in_p_create_infos; - if (original_result >= 0 && !options_.replace_dir.empty()) + if (original_result >= 0 && !options_.replace_shader_dir.empty()) { uint32_t num_bytes = graphics::vulkan_struct_deep_copy(in_p_create_infos, create_info_count, nullptr); create_info_data.resize(num_bytes); @@ -10003,7 +10098,7 @@ std::function()> VulkanReplayConsumer auto create_infos = reinterpret_cast(create_info_data.data()); std::vector> replaced_file_code; - if (returnValue >= 0 && !options_.replace_dir.empty()) + if (returnValue >= 0 && !options_.replace_shader_dir.empty()) { replaced_file_code = ReplaceShaders(createInfoCount, create_infos, pipelines.data()); } @@ -10138,7 +10233,7 @@ VulkanReplayConsumerBase::AsyncCreateShadersEXT(const ApiCallInfo& auto create_infos = reinterpret_cast(create_info_data.data()); std::vector> replaced_file_code; - if (returnValue >= 0 && !options_.replace_dir.empty()) + if (returnValue >= 0 && !options_.replace_shader_dir.empty()) { replaced_file_code = ReplaceShaders(createInfoCount, create_infos, shaders.data()); } diff --git a/framework/decode/vulkan_replay_consumer_base.h b/framework/decode/vulkan_replay_consumer_base.h index aa02e92e1f..14098b3c0d 100644 --- a/framework/decode/vulkan_replay_consumer_base.h +++ b/framework/decode/vulkan_replay_consumer_base.h @@ -237,15 +237,76 @@ class VulkanReplayConsumerBase : public VulkanConsumer return MapHandle(capture_id, &CommonObjectInfoTable::GetVkDeviceInfo); } + const encode::VulkanInstanceTable* GetInstanceTable(const void* handle) const; + + const encode::VulkanDeviceTable* GetDeviceTable(const void* handle) const; + void AddImageHandle(format::HandleId parent_id, format::HandleId id, VkImage handle, VulkanImageInfo&& initial_info) + { + AddHandle( + parent_id, &id, &handle, std::move(initial_info), &VulkanObjectInfoTable::AddVkImageInfo); + } + + // Utilities for correctly setting up a vulkan create instance/device calls. Shared with OpenXR + // Store for the "modified for replay" instance create info, and all referenced memory + struct CreateInstanceInfoState + { + std::vector modified_layers; + std::vector modified_extensions; + VkInstanceCreateInfo modified_create_info; + }; + // create_state passed in by reference to conserve pointers to member variable + // Not initialized in a CreateDeviceInfoState constructor as *many* VulkanReplayConsumerBase + // member functions and variables are referenced + void ModifyCreateInstanceInfo(const StructPointerDecoder* pCreateInfo, + CreateInstanceInfoState& create_state); + + void PostCreateInstanceUpdateState(VkInstance replay_instance, + const VkInstanceCreateInfo& modified_create_info, + VulkanInstanceInfo& instance_info); + + // Store for the "modified for replay" device create info, and all referenced memory + struct CreateDeviceInfoState + { + VkDeviceCreateInfo modified_create_info; + std::vector modified_extensions; + std::vector trim_extensions; + VkDeviceGroupDeviceCreateInfo modified_device_group_create_info; + std::vector replay_device_group; + graphics::VulkanDeviceUtil device_util; + graphics::VulkanDevicePropertyFeatureInfo property_feature_info; + }; + + // create_state passed in by reference to conserve pointers to member variable + // Not initialized in a CreateDeviceInfoState constructor as *many* VulkanReplayConsumerBase + // member functions and variables are referenced + void ModifyCreateDeviceInfo(VulkanPhysicalDeviceInfo* physical_device_info, + const StructPointerDecoder* pCreateInfo, + CreateDeviceInfoState& create_state); + + VkResult PostCreateDeviceUpdateState(VulkanPhysicalDeviceInfo* physical_device_info, + VkDevice replay_device, + CreateDeviceInfoState& create_state, + VulkanDeviceInfo* device_info); + + void CheckResult(const char* func_name, VkResult original, VkResult replay, const decode::ApiCallInfo& call_info); + + PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() + { + if (loader_handle_ == nullptr) + InitializeLoader(); // Ensures GIPA is set + return get_instance_proc_addr_; + } + + void SetPhysicalDeviceAlias(format::HandleId instance, VulkanPhysicalDeviceInfo& replay_physical_device); + + // Need the side effects from this when creating vulkan devices from OpenXr + void GetMatchingDevice(VulkanPhysicalDeviceInfo* physical_device_info); + protected: const CommonObjectInfoTable& GetObjectInfoTable() const { return *object_info_table_; } CommonObjectInfoTable& GetObjectInfoTable() { return *object_info_table_; } - const encode::VulkanInstanceTable* GetInstanceTable(const void* handle) const; - - const encode::VulkanDeviceTable* GetDeviceTable(const void* handle) const; - void* PreProcessExternalObject(uint64_t object_id, format::ApiCallId call_id, const char* call_name); void PostProcessExternalObject( @@ -254,8 +315,6 @@ class VulkanReplayConsumerBase : public VulkanConsumer const VkAllocationCallbacks* GetAllocationCallbacks(const StructPointerDecoder* original_callbacks); - void CheckResult(const char* func_name, VkResult original, VkResult replay, const decode::ApiCallInfo& call_info); - template typename T::HandleType MapHandle(format::HandleId id, const T* (CommonObjectInfoTable::*MapFunc)(format::HandleId) const) const diff --git a/framework/decode/vulkan_replay_options.h b/framework/decode/vulkan_replay_options.h index 7771a66d58..65e6c75f5c 100644 --- a/framework/decode/vulkan_replay_options.h +++ b/framework/decode/vulkan_replay_options.h @@ -57,9 +57,7 @@ static constexpr int kUnspecifiedColorAttachment = -1; struct VulkanReplayOptions : public ReplayOptions { bool enable_vulkan{ true }; - bool skip_failed_allocations{ false }; bool omit_pipeline_cache_data{ false }; - bool remove_unsupported_features{ false }; bool use_colorspace_fallback{ false }; bool offscreen_swapchain_frame_boundary{ false }; util::SwapchainOption swapchain_option{ util::SwapchainOption::kVirtual }; @@ -67,13 +65,9 @@ struct VulkanReplayOptions : public ReplayOptions int32_t override_gpu_group_index{ -1 }; int32_t surface_index{ -1 }; CreateResourceAllocator create_resource_allocator; - util::ScreenshotFormat screenshot_format{ util::ScreenshotFormat::kBmp }; - std::vector screenshot_ranges; - std::string screenshot_dir; - std::string screenshot_file_prefix{ kDefaultScreenshotFilePrefix }; uint32_t screenshot_width, screenshot_height; float screenshot_scale; - std::string replace_dir; + std::string replace_shader_dir; SkipGetFenceStatus skip_get_fence_status{ SkipGetFenceStatus::NoSkip }; std::vector skip_get_fence_ranges; bool wait_before_present{ false }; diff --git a/framework/encode/api_capture_manager.h b/framework/encode/api_capture_manager.h index f5e453c10b..9f2e3d177c 100644 --- a/framework/encode/api_capture_manager.h +++ b/framework/encode/api_capture_manager.h @@ -186,6 +186,7 @@ class ApiCaptureManager bool IsTrimEnabled() const { return common_manager_->IsTrimEnabled(); } uint32_t GetCurrentFrame() const { return common_manager_->GetCurrentFrame(); } CommonCaptureManager::CaptureMode GetCaptureMode() const { return common_manager_->GetCaptureMode(); } + void SetCaptureMode(CommonCaptureManager::CaptureMode mode) { common_manager_->SetCaptureMode(mode); } bool GetDebugLayerSetting() const { return common_manager_->GetDebugLayerSetting(); } bool GetDebugDeviceLostSetting() const { return common_manager_->GetDebugDeviceLostSetting(); } bool GetDisableDxrSetting() const { return common_manager_->GetDisableDxrSetting(); } diff --git a/framework/encode/capture_manager.h b/framework/encode/capture_manager.h index b54f4e59e5..4423c1def2 100644 --- a/framework/encode/capture_manager.h +++ b/framework/encode/capture_manager.h @@ -260,6 +260,7 @@ class CommonCaptureManager bool IsTrimEnabled() const { return trim_enabled_; } uint32_t GetCurrentFrame() const { return current_frame_; } CaptureMode GetCaptureMode() const { return capture_mode_; } + void SetCaptureMode(CaptureMode new_mode) { capture_mode_ = new_mode; } bool GetDebugLayerSetting() const { return debug_layer_; } bool GetDebugDeviceLostSetting() const { return debug_device_lost_; } bool GetDisableDxrSetting() const { return disable_dxr_; } diff --git a/tools/replay/android_main.cpp b/tools/replay/android_main.cpp index a20c740e8d..1abf506ea0 100644 --- a/tools/replay/android_main.cpp +++ b/tools/replay/android_main.cpp @@ -1,6 +1,6 @@ /* ** Copyright (c) 2018-2020 Valve Corporation -** Copyright (c) 2018-2020 LunarG, Inc. +** Copyright (c) 2018-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"), @@ -133,8 +133,8 @@ void android_main(struct android_app* app) return; } - gfxrecon::decode::VulkanReplayConsumer replay_consumer(application, replay_options); - gfxrecon::decode::VulkanDecoder decoder; + gfxrecon::decode::VulkanReplayConsumer vulkan_replay_consumer(application, replay_options); + gfxrecon::decode::VulkanDecoder vulkan_decoder; uint32_t start_frame, end_frame; bool has_mfr = GetMeasurementFrameRange(arg_parser, start_frame, end_frame); std::string measurement_file_name; @@ -153,12 +153,13 @@ void android_main(struct android_app* app) replay_options.preload_measurement_range, measurement_file_name); - replay_consumer.SetFatalErrorHandler([](const char* message) { throw std::runtime_error(message); }); - replay_consumer.SetFpsInfo(&fps_info); + vulkan_replay_consumer.SetFatalErrorHandler( + [](const char* message) { throw std::runtime_error(message); }); + vulkan_replay_consumer.SetFpsInfo(&fps_info); - decoder.AddConsumer(&replay_consumer); + vulkan_decoder.AddConsumer(&vulkan_replay_consumer); - file_processor->AddDecoder(&decoder); + file_processor->AddDecoder(&vulkan_decoder); application->SetPauseFrame(GetPauseFrame(arg_parser)); diff --git a/tools/tool_settings.h b/tools/tool_settings.h index f459f8362a..239d6ec9a0 100644 --- a/tools/tool_settings.h +++ b/tools/tool_settings.h @@ -1019,7 +1019,7 @@ GetVulkanReplayOptions(const gfxrecon::util::ArgumentParser& arg_parse replay_options.virtual_swapchain_skip_blit = true; } - replay_options.replace_dir = arg_parser.GetArgumentValue(kShaderReplaceArgument); + replay_options.replace_shader_dir = arg_parser.GetArgumentValue(kShaderReplaceArgument); replay_options.create_resource_allocator = GetCreateResourceAllocatorFunc(arg_parser, filename, replay_options, tracked_object_info_table);