[Frame looping] [Prototype] [Not to Merge] Make it compatible with more games#3047
[Frame looping] [Prototype] [Not to Merge] Make it compatible with more games#3047olehkuznetsov wants to merge 27 commits into
Conversation
This CL introduces a robust state-restoration mechanism for Vulkan frame
looping to resolve deadlocks caused by fence state drift between loop
iterations (e.g., in Fortnite).
To keep the core framework clean and avoid intrusive changes to the
generic FileProcessor class, a "dual-capture" architecture is introduced:
1. For N = 1 (looping Frame 1): Fence states are captured at the end of
the setup phase via the consumer's ProcessStateEndMarker().
2. For N > 1 (looping Frame N): Fence states are captured immediately at
the Frame N boundary via the decoder's OnLoopStart() event.
To ensure stability, the consumer waits for all Vulkan devices to be idle
(reusing the inherited WaitDevicesIdle() helper) before querying and
storing the initial fence states.
At the loop boundary, we perform a spec-compliant, highly optimized fixup:
- Fences that drifted from UNSIGNALED -> SIGNALED are collected in
'fences_to_reset' and reset back to UNSIGNALED via vkResetFences.
- Fences that drifted from SIGNALED -> UNSIGNALED are collected in
'fences_to_signal' and synthetically signaled via vkQueueSubmit (without
any redundant reset calls).
All redundant logging overrides in the frame loop consumer have been
purged to keep the implementation minimal and efficient.
This CL resolves a SIGSEGV crash occurring during the final iteration of
Vulkan frame looping, particularly on traces with frequent descriptor pool
resets.
Problem: Asymmetric Skipping of Resource Lifecycle
- To optimize repetitions, the frame loop consumer skips resource
creations/allocations (e.g., descriptor sets). However, it previously
did NOT skip destructions/resets (like vkResetDescriptorPool) during the
final iteration, in an attempt to clean up.
- This created a fatal asymmetry: at the start of the final iteration,
replayed pool resets would execute and destroy the sets, but the
subsequent allocation calls in the frame would be skipped.
- This resulted in invalid/null descriptor set handles being passed to draw
calls during the final iteration, causing a driver-level SIGSEGV.
Fix: Symmetric Skipping
- Removed the `!IsFinalIteration()` constraint from descriptor pool
and set destructions/resets.
- We now symmetrically skip destructions/resets throughout the entire
looping range, including the final iteration.
- This keeps the reused resources alive and valid on the GPU until the
end of the replay. Since the replay process exits shortly after, the
OS/driver safely cleans up all leaked resources.
Tested:
- Verified that traces with frequent pool resets now loop successfully
without crashing on the second (final) iteration.
Add vkCreateCommandPool to the generated frame-looping overrides so that command pools created within the loop range are correctly tracked and subsequently destroyed on the final iteration of the loop. Also update the manual VulkanReplayFrameLoopConsumer override to delegate to the generated base class version to ensure proper handle tracking, while maintaining the necessary command buffer reset flag modifications. TAG=agy CONV=a0864ce4-0126-408e-ad0b-5302cffe1ff3
…ooping Override Process_vkCmdWriteTimestamp in VulkanReplayFrameLoopConsumer to skip writing timestamps on loop repetitions. This avoids "query not reset" validation errors when replaying traces that do not reset queries within the looped frame. TAG=agy CONV=a0864ce4-0126-408e-ad0b-5302cffe1ff3
Apply official clang-format guidelines to all hand-written files modified in our frame-looping fixes: - api_decoder.h - preload_file_processor.cpp - vulkan_decoder_base.h - vulkan_replay_frame_loop_consumer.cpp - vulkan_replay_frame_loop_consumer.h TAG=agy CONV=a0864ce4-0126-408e-ad0b-5302cffe1ff3
c43f527 to
8e61269
Compare
|
Need to sync with this PR #3052 |
|
I think that maybe if |
1b867e6 to
fdef886
Compare
# Conflicts: # framework/decode/vulkan_replay_frame_loop_consumer.cpp # framework/decode/vulkan_replay_frame_loop_consumer.h
…tive queue tracking
fdef886 to
bc1b48e
Compare
Add a new 'skipDuringLooping' category to replay_frame_loop_overrides.json containing all Vulkan query recording, harvesting, and reset entry points. Update code generator scripts to automatically generate no-op overrides during looping for commands in this category, and remove redundant manual overrides from VulkanReplayFrameLoopConsumer.
Add replay overrides for vkCmdWaitEvents and vkCmdWaitEvents2 Register replay override hooks for vkCmdWaitEvents, vkCmdWaitEvents2, and vkCmdWaitEvents2KHR in replay_overrides.json so code generation routes these commands through virtual methods on VulkanReplayConsumerBase. Implement base overrides in VulkanReplayConsumerBase that execute the underlying API calls while tracking image memory barrier layout transitions in command_buffer_info->image_layout_barriers and VulkanImageInfo::intermediate_layout. This aligns wait event layout tracking with existing pipeline barrier tracking and enables derived consumers (such as VulkanReplayFrameLoopConsumer) to observe layout transitions performed by event waits.
|
@olehkuznetsov , when possible it's helpful to us for review purposes to make multiple smaller PRs that each contain well-encapsulated changes to the code. It this PR a series of changes that are accumulating as you test more and more titles? If so, please take a moment to break it into smaller PRs or we can discuss outside GitHub whether LunarG should break the PR apart for you. Also, if you believe you've resolved the feedback given in review, please either note that you've applied the change or respond why you think there's an issue with the feedback. Thank you! |
|
@olehkuznetsov Making a change to .clang-format is project wide shouldn't be made lightly; I note your commit contains no details on the change. Can you explain in more detail the benefit of the changes you're proposing in the .clang-format file? |
Seems as clang-format-14 is not available for me, so, goal of those changes are to make newer versions of clang-format to be compatible with clang-format-14 |
The idea here is to share prototype code which works with more cases, so, Antonio and Nick can get insights and apply ideas from this prototype. This one should not be submitted - I've updated title to make it clear. |
This commit addresses two major issues when replaying captures in frame loop mode: 1. Null Pointer Dereference in OverrideGetFenceStatus: Handled a case where vkGetFenceStatus is invoked on a fence that could not be created or tracked properly during replay (resulting in a null fence_info). We now safely return VK_SUCCESS instead of crashing. 2. Validation Layer Abort on Strict Drivers (e.g. Qualcomm Adreno): When looping a frame, submitting a fence that was already signaled in the previous iteration violates the Vulkan spec (VUID-vkQueueSubmit-fence-00063) and can cause fatal driver hangs or validation layer aborts (std::future_error). To safeguard against this, we now explicitly call vkResetFences on any provided fence immediately prior to vkQueueSubmit, vkQueueSubmit2, and vkQueueBindSparse. Also updated frame_loop_sync_fences_events.md to document this new in-loop submission safeguard.
Refactored fences
Modified some resources destruction
Ignore vkCmdWriteTimestamp