Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 130 additions & 19 deletions framework/decode/vulkan_replay_consumer_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9322,17 +9322,24 @@ VkResult VulkanReplayConsumerBase::OverrideCreateRayTracingPipelinesKHR(
const StructPointerDecoder<Decoded_VkAllocationCallbacks>* pAllocator,
HandlePointerDecoder<VkPipeline>* pPipelines)
{
GFXRECON_UNREFERENCED_PARAMETER(original_result);
GFXRECON_ASSERT(device_info != nullptr && pCreateInfos != nullptr && pAllocator != nullptr &&
pPipelines != nullptr && !pPipelines->IsNull() && pPipelines->GetHandlePointer() != nullptr);

assert((device_info != nullptr) && (pCreateInfos != nullptr) && (pAllocator != nullptr) &&
(pPipelines != nullptr) && !pPipelines->IsNull() && (pPipelines->GetHandlePointer() != nullptr));
if (SkipPipelineCreationForCompileRequired(original_result, pPipelines))
{
return original_result;
}

VkResult result = VK_SUCCESS;
VkDevice device = device_info->handle;
const VkRayTracingPipelineCreateInfoKHR* in_pCreateInfos = pCreateInfos->GetPointer();
const VkAllocationCallbacks* in_pAllocator = GetAllocationCallbacks(pAllocator);
VkPipeline* out_pPipelines = pPipelines->GetHandlePointer();
VkDeferredOperationKHR in_deferredOperation =

// remove potential flag
RemoveFailOnCompileRequiredFlags(const_cast<VkRayTracingPipelineCreateInfoKHR*>(in_pCreateInfos), createInfoCount);

const VkAllocationCallbacks* in_pAllocator = GetAllocationCallbacks(pAllocator);
VkPipeline* out_pPipelines = pPipelines->GetHandlePointer();
VkDeferredOperationKHR in_deferredOperation =
(deferred_operation_info != nullptr) ? deferred_operation_info->handle : VK_NULL_HANDLE;
VkPipelineCache in_pipelineCache = (pipeline_cache_info != nullptr) ? pipeline_cache_info->handle : VK_NULL_HANDLE;
VkPipelineCache overridePipelineCache = in_pipelineCache;
Expand Down Expand Up @@ -9701,10 +9708,17 @@ VkResult VulkanReplayConsumerBase::OverrideCreateRayTracingPipelinesNV(
const StructPointerDecoder<Decoded_VkAllocationCallbacks>* pAllocator,
HandlePointerDecoder<VkPipeline>* pPipelines)
{
GFXRECON_UNREFERENCED_PARAMETER(original_result);
GFXRECON_ASSERT(device_info != nullptr && createInfoCount > 0 && pCreateInfos != nullptr && pPipelines != nullptr &&
pCreateInfos->GetPointer() != nullptr && pPipelines->GetHandlePointer() != nullptr);

assert((device_info != nullptr) && (createInfoCount > 0) && (pCreateInfos != nullptr) && (pPipelines != nullptr) &&
(pCreateInfos->GetPointer() != nullptr) && (pPipelines->GetHandlePointer() != nullptr));
if (SkipPipelineCreationForCompileRequired(original_result, pPipelines))
{
return original_result;
}

const VkRayTracingPipelineCreateInfoNV* in_pCreateInfos = pCreateInfos->GetPointer();

RemoveFailOnCompileRequiredFlags(const_cast<VkRayTracingPipelineCreateInfoNV*>(in_pCreateInfos), createInfoCount);

VkPipelineCache pipelineCache = (pipeline_cache_info == nullptr) ? VK_NULL_HANDLE : pipeline_cache_info->handle;
VkPipelineCache overridePipelineCache = pipelineCache;
Expand All @@ -9721,7 +9735,7 @@ VkResult VulkanReplayConsumerBase::OverrideCreateRayTracingPipelinesNV(
VkResult result = func(device_info->handle,
overridePipelineCache,
createInfoCount,
pCreateInfos->GetPointer(),
in_pCreateInfos,
GetAllocationCallbacks(pAllocator),
pPipelines->GetHandlePointer());

Expand Down Expand Up @@ -11606,6 +11620,71 @@ void VulkanReplayConsumerBase::OverrideUpdateDescriptorSets(
}
}

bool VulkanReplayConsumerBase::SkipPipelineCreationForCompileRequired(VkResult original_result,
HandlePointerDecoder<VkPipeline>* pipelines)
{
GFXRECON_ASSERT(pipelines != nullptr && !pipelines->IsNull() && pipelines->GetHandlePointer() != nullptr);

if (original_result == VK_PIPELINE_COMPILE_REQUIRED)
{
GFXRECON_LOG_WARNING("Skipping execution of VkPipeline creation due to original result being "
"VK_PIPELINE_COMPILE_REQUIRED(_EXT). Returning VK_NULL_HANDLE for created pipeline.");

VkPipeline* handles = pipelines->GetHandlePointer();
for (uint32_t i = 0; i < pipelines->GetLength(); ++i)
{
handles[i] = VK_NULL_HANDLE;
}
return true;
}
return false;
}

template <typename T>
void VulkanReplayConsumerBase::RemoveFailOnCompileRequiredFlags(T* create_infos, uint32_t create_info_count)
{
static_assert(std::is_same_v<T, VkGraphicsPipelineCreateInfo> || std::is_same_v<T, VkComputePipelineCreateInfo> ||
std::is_same_v<T, VkRayTracingPipelineCreateInfoKHR> ||
std::is_same_v<T, VkRayTracingPipelineCreateInfoNV>,
"only Vk***PipelineCreateInfo types supported");

std::string pipeline_type_str;

if constexpr (std::is_same_v<T, VkGraphicsPipelineCreateInfo>)
{
pipeline_type_str = "graphics pipeline";
}
else if constexpr (std::is_same_v<T, VkComputePipelineCreateInfo>)
{
pipeline_type_str = "compute pipeline";
}
else if constexpr (std::is_same_v<T, VkRayTracingPipelineCreateInfoKHR>)
{
pipeline_type_str = "raytracing pipeline (KHR)";
}
else if constexpr (std::is_same_v<T, VkRayTracingPipelineCreateInfoNV>)
{
pipeline_type_str = "raytracing pipeline (NV)";
}

if (create_infos == nullptr)
{
return;
}

for (uint32_t i = 0; i < create_info_count; ++i)
{
if (create_infos[i].flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT)
{
create_infos[i].flags &= ~VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
GFXRECON_LOG_WARNING("Removed VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT flag from a %s - "
"create-info index: %u during replay.",
pipeline_type_str.c_str(),
i);
}
}
}

[[nodiscard]] std::vector<std::unique_ptr<char[]>> VulkanReplayConsumerBase::ReplaceShaders(
uint32_t create_info_count, VkGraphicsPipelineCreateInfo* create_infos, const format::HandleId* pipelines) const
{
Expand Down Expand Up @@ -11679,6 +11758,14 @@ VkResult VulkanReplayConsumerBase::OverrideCreateGraphicsPipelines(
VkPipeline* out_pipelines = pPipelines->GetHandlePointer();
VkPipelineCache pipeline_cache = (pipeline_cache_info != nullptr) ? pipeline_cache_info->handle : VK_NULL_HANDLE;

if (SkipPipelineCreationForCompileRequired(original_result, pPipelines))
{
return original_result;
}

// remove potential VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT during replay
RemoveFailOnCompileRequiredFlags(const_cast<VkGraphicsPipelineCreateInfo*>(in_p_create_infos), create_info_count);

// If there is no pipeline cache and we want to create a new one
format::HandleId cache_pipeline_id = format::kNullHandleId;
if (pipeline_cache == VK_NULL_HANDLE && options_.add_new_pipeline_caches)
Expand Down Expand Up @@ -11740,15 +11827,22 @@ VkResult VulkanReplayConsumerBase::OverrideCreateComputePipelines(
const StructPointerDecoder<Decoded_VkAllocationCallbacks>* pAllocator,
HandlePointerDecoder<VkPipeline>* pPipelines)
{
GFXRECON_UNREFERENCED_PARAMETER(original_result);
GFXRECON_ASSERT(device_info != nullptr && pCreateInfos != nullptr && pAllocator != nullptr &&
pPipelines != nullptr && !pPipelines->IsNull() && pPipelines->GetHandlePointer() != nullptr);

GFXRECON_ASSERT((device_info != nullptr) && (pCreateInfos != nullptr) && (pAllocator != nullptr) &&
(pPipelines != nullptr) && !pPipelines->IsNull() && (pPipelines->GetHandlePointer() != nullptr));
if (SkipPipelineCreationForCompileRequired(original_result, pPipelines))
{
return original_result;
}

VkDevice in_device = device_info->handle;
const VkComputePipelineCreateInfo* in_p_create_infos = pCreateInfos->GetPointer();

// remove potential flag
RemoveFailOnCompileRequiredFlags(const_cast<VkComputePipelineCreateInfo*>(in_p_create_infos), create_info_count);

VkDevice in_device = device_info->handle;
const VkComputePipelineCreateInfo* in_p_create_infos = pCreateInfos->GetPointer();
const VkAllocationCallbacks* in_p_allocation_callbacks = GetAllocationCallbacks(pAllocator);
VkPipeline* out_pipelines = pPipelines->GetHandlePointer();
const VkAllocationCallbacks* in_p_allocation_callbacks = GetAllocationCallbacks(pAllocator);
VkPipeline* out_pipelines = pPipelines->GetHandlePointer();
VkPipelineCache pipeline_cache = (pipeline_cache_info != nullptr) ? pipeline_cache_info->handle : VK_NULL_HANDLE;

// If there is no pipeline cache and we want to create a new one
Expand Down Expand Up @@ -12086,15 +12180,24 @@ std::function<decode::handle_create_result_t<VkPipeline>()> VulkanReplayConsumer
HandlePointerDecoder<VkPipeline>* pPipelines)
{
// avoid async operations if an externally synchronized pipeline-cache is used
if (pipeline_cache_info != nullptr && pipeline_cache_info->requires_external_synchronization)
bool avoid_async_op = pipeline_cache_info != nullptr && pipeline_cache_info->handle != VK_NULL_HANDLE;

// avoid async operations when VK_PIPELINE_COMPILE_REQUIRED was returned during capture
avoid_async_op = avoid_async_op || SkipPipelineCreationForCompileRequired(returnValue, pPipelines);

if (avoid_async_op)
{
return {};
}

const VkGraphicsPipelineCreateInfo* in_pCreateInfos = pCreateInfos->GetPointer();
const VkAllocationCallbacks* in_pAllocator = GetAllocationCallbacks(pAllocator);
VkDevice device_handle = device_info->handle;
VkPipelineCache pipeline_cache = (pipeline_cache_info != nullptr) ? pipeline_cache_info->handle : VK_NULL_HANDLE;

// remove potential VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT during replay
RemoveFailOnCompileRequiredFlags(pCreateInfos->GetPointer(), createInfoCount);

// If there is no pipeline cache and we want to create a new one
format::HandleId cache_pipeline_id = format::kNullHandleId;
if (pipeline_cache == VK_NULL_HANDLE && options_.add_new_pipeline_caches)
Expand Down Expand Up @@ -12197,7 +12300,12 @@ std::function<handle_create_result_t<VkPipeline>()> VulkanReplayConsumerBase::As
HandlePointerDecoder<VkPipeline>* pPipelines)
{
// avoid async operations if an externally synchronized pipeline-cache is used
if (pipeline_cache_info != nullptr && pipeline_cache_info->requires_external_synchronization)
bool avoid_async_op = pipeline_cache_info != nullptr && pipeline_cache_info->handle != VK_NULL_HANDLE;

// avoid async operations when VK_PIPELINE_COMPILE_REQUIRED was returned during capture
avoid_async_op = avoid_async_op || SkipPipelineCreationForCompileRequired(returnValue, pPipelines);

if (avoid_async_op)
{
return {};
}
Expand All @@ -12207,6 +12315,9 @@ std::function<handle_create_result_t<VkPipeline>()> VulkanReplayConsumerBase::As
VkDevice device_handle = device_info->handle;
VkPipelineCache pipeline_cache = (pipeline_cache_info != nullptr) ? pipeline_cache_info->handle : VK_NULL_HANDLE;

// remove potential VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT during replay
RemoveFailOnCompileRequiredFlags(const_cast<VkComputePipelineCreateInfo*>(in_pCreateInfos), createInfoCount);

// If there is no pipeline cache and we want to create a new one
format::HandleId cache_pipeline_id = format::kNullHandleId;
if (pipeline_cache == VK_NULL_HANDLE && options_.add_new_pipeline_caches)
Expand Down
24 changes: 24 additions & 0 deletions framework/decode/vulkan_replay_consumer_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -1879,6 +1879,30 @@ class VulkanReplayConsumerBase : public VulkanConsumer
typedef std::unordered_map<uint64_t, HardwareBufferInfo> HardwareBufferMap;
typedef std::unordered_map<format::HandleId, HardwareBufferMemoryInfo> HardwareBufferMemoryMap;

/**
* @brief SkipPipelineCreationForCompileRequired will check 'original_result' and return true,
* if it matches VK_PIPELINE_COMPILE_REQUIRED. otherwise returns false and does nothing.
*
* in case original_result == VK_PIPELINE_COMPILE_REQUIRED, all VkPipeline-handles contained in
* 'pipelines' will be set to VK_NULL_HANDLE and a warning will be logged.
*
* @param original_result original return-value of a VkCreateXXXPipelines call
* @param pipelines provided decoder containing pipeline-handles
* @return true if original_result == VK_PIPELINE_COMPILE_REQUIRED
*/
static bool SkipPipelineCreationForCompileRequired(VkResult original_result,
HandlePointerDecoder<VkPipeline>* pipelines);

/**
*
* @brief RemoveFailOnCompileRequiredFlags will check and remove potential
* 'VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT' flags from an array of
* VkPipeline create-infos. Will log individual warnings for each removed flag.
*
*/
template <typename CreateInfo>
static void RemoveFailOnCompileRequiredFlags(CreateInfo* create_infos, uint32_t create_info_count);

private:
util::platform::LibraryHandle loader_handle_;
PFN_vkGetInstanceProcAddr get_instance_proc_addr_;
Expand Down
2 changes: 1 addition & 1 deletion framework/encode/capture_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ class CaptureSettings
uint32_t accel_struct_padding{ 0 };
bool force_command_serialization{ false };
bool queue_zero_only{ false };
bool allow_pipeline_compile_required{ false };
bool allow_pipeline_compile_required{ true };
bool quit_after_frame_ranges{ false };
bool force_fifo_present_mode{ true };
bool use_asset_file{ false };
Expand Down
Loading