Skip to content

[Frame looping] [Prototype] [Not to Merge] Make it compatible with more games#3047

Draft
olehkuznetsov wants to merge 27 commits into
LunarG:devfrom
olehkuznetsov:frame-looping-fix-upstream
Draft

[Frame looping] [Prototype] [Not to Merge] Make it compatible with more games#3047
olehkuznetsov wants to merge 27 commits into
LunarG:devfrom
olehkuznetsov:frame-looping-fix-upstream

Conversation

@olehkuznetsov

Copy link
Copy Markdown
Contributor

Refactored fences
Modified some resources destruction
Ignore vkCmdWriteTimestamp

    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
@olehkuznetsov
olehkuznetsov requested a review from a team as a code owner June 24, 2026 17:58
@CLAassistant

CLAassistant commented Jun 24, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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
Comment thread framework/decode/vulkan_replay_frame_loop_consumer.cpp Outdated
Comment thread framework/decode/vulkan_decoder_base.h
Comment thread framework/decode/vulkan_replay_frame_loop_consumer.cpp Outdated
Comment thread framework/decode/vulkan_replay_frame_loop_consumer.cpp
Comment thread framework/decode/preload_file_processor.cpp
@antonio-lunarg

Copy link
Copy Markdown
Contributor

Need to sync with this PR #3052

@nickdriscoll-lunarg

Copy link
Copy Markdown
Contributor

I think that maybe if vkCreateFence was overridden to reset the fence on subsequent iterations of the loop frame, then this PR can supersede #3052. Otherwise the case of "fence was created and used during the loop range" is the one thing my PR handles that this one doesn't.

@olehkuznetsov
olehkuznetsov force-pushed the frame-looping-fix-upstream branch from 1b867e6 to fdef886 Compare June 29, 2026 18:06
@olehkuznetsov
olehkuznetsov force-pushed the frame-looping-fix-upstream branch from fdef886 to bc1b48e Compare June 30, 2026 11:03
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.
@bradgrantham-lunarg

Copy link
Copy Markdown
Contributor

@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!

@bradgrantham-lunarg

Copy link
Copy Markdown
Contributor

@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?

@olehkuznetsov olehkuznetsov changed the title [Frame looping] Make it compatible with more games [Frame looping] [Prototype] Make it compatible with more games Jul 6, 2026
@olehkuznetsov

Copy link
Copy Markdown
Contributor Author

@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

@olehkuznetsov olehkuznetsov changed the title [Frame looping] [Prototype] Make it compatible with more games [Frame looping] [Prototype] [Not to Merge] Make it compatible with more games Jul 6, 2026
@olehkuznetsov

Copy link
Copy Markdown
Contributor Author

@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!

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.

@antonio-lunarg
antonio-lunarg marked this pull request as draft July 7, 2026 08:38
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants