Skip to content

feat(plugin): add state loading complete event to plugin ABI#9

Open
shukangz wants to merge 2 commits into
android-graphics:devfrom
shukangz:rdc_plugin_new_event
Open

feat(plugin): add state loading complete event to plugin ABI#9
shukangz wants to merge 2 commits into
android-graphics:devfrom
shukangz:rdc_plugin_new_event

Conversation

@shukangz

@shukangz shukangz commented Jul 7, 2026

Copy link
Copy Markdown

Add GFXR_REPLAY_EVENT_STATE_LOADING_COMPLETE to notify external modules when the initial state loading has completed during Vulkan replays.

This update includes the event struct definition, integration with the replay event sink, and relevant test coverage.

shukangz added 2 commits July 6, 2026 20:53
Add GFXR_REPLAY_EVENT_STATE_LOADING_COMPLETE to notify external
modules when the initial state loading has completed during Vulkan
replays.

This update includes the event struct definition, integration with
the replay event sink, and relevant test coverage.

@olehkuznetsov olehkuznetsov left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? Why it doesn't work with GFXR_REPLAY_EVENT_FRAME_BEGIN ?

setup is not guaranteed to be present in non trimmed captures and also this approach will not work if we have multiframe capture and want to export to render doc 3rd frame./

@shukangz

shukangz commented Jul 8, 2026

Copy link
Copy Markdown
Author

You are right that "state setup" may not exist in an untrimmed trace, but using FRAME_BEGIN on trimmed traces have complexities.

In a trimmed capture (e.g., a capture of frames 100–105), the first replayed frame (index 0) contains a large "state setup" block. This block recreates all Vulkan resources (devices, buffers, textures, descriptor sets, etc.) to match their state at the start of the trim. If we start capturing at FRAME_BEGIN, which fires before the frame's blocks are replayed, RenderDoc will capture all of these setup API calls. This pollutes the captured frame with thousands of resource creation calls.

If using frame looping to avoid the "state setup" block, the resulting .rdc file would contain large initial state blocks of raw pixel buffers from previous loop iterations. The capture time would be longer for more replaying. This may not be concern today but may grow into one if we extend the support to multiple frame capture later. See discussion at [1].

I have write the RenderDoc plugin so it can support both trimmed (triggered by STATE_LOADING_COMPLETE) and untrimmed traces (triggered by FRAME_BEGIN). Please see on_event(GfxrReplayPluginV1* self, const GfxrReplayEventHeader* event) in [2].

[1] https://docs.google.com/document/d/1f32495O7CU27rEGWEOvLpiEfBU8ARt5RDyT13FHaPFc/edit?resourcekey=0--HC4JFRwnTrNiDQOSjRY5g&disco=AAAB-u3ol-o
[2] 2fb60d9#diff-14198bed8d51a7bf5dc4ef159218e71ec04fa1f112cf62d60af09536f26c41afR225

@olehkuznetsov

Copy link
Copy Markdown

You are right that "state setup" may not exist in an untrimmed trace, but using FRAME_BEGIN on trimmed traces have complexities.

In a trimmed capture (e.g., a capture of frames 100–105), the first replayed frame (index 0) contains a large "state setup" block. This block recreates all Vulkan resources (devices, buffers, textures, descriptor sets, etc.) to match their state at the start of the trim. If we start capturing at FRAME_BEGIN, which fires before the frame's blocks are replayed, RenderDoc will capture all of these setup API calls. This pollutes the captured frame with thousands of resource creation calls.

If using frame looping to avoid the "state setup" block, the resulting .rdc file would contain large initial state blocks of raw pixel buffers from previous loop iterations. The capture time would be longer for more replaying. This may not be concern today but may grow into one if we extend the support to multiple frame capture later. See discussion at [1].

I have write the RenderDoc plugin so it can support both trimmed (triggered by STATE_LOADING_COMPLETE) and untrimmed traces (triggered by FRAME_BEGIN). Please see on_event(GfxrReplayPluginV1* self, const GfxrReplayEventHeader* event) in [2].

[1] https://docs.google.com/document/d/1f32495O7CU27rEGWEOvLpiEfBU8ARt5RDyT13FHaPFc/edit?resourcekey=0--HC4JFRwnTrNiDQOSjRY5g&disco=AAAB-u3ol-o [2] 2fb60d9#diff-14198bed8d51a7bf5dc4ef159218e71ec04fa1f112cf62d60af09536f26c41afR225

Let's insted fix FRAME_BEGIN, so, it doesn't include setup state.

Alternatively, you can try to start capture not on the FRAME BEGIN envet, but on the first Queue Submit of the frame.

@shukangz

shukangz commented Jul 9, 2026

Copy link
Copy Markdown
Author

I agree that the first proposal (fixing FRAME_BEGIN so it doesn't include the setup state) is architecturally the correct solution. Conceptually, the state setup sequence injected by the trimmer shouldn't bleed into what we define as the workload of the first replayed frame.

However, since we are maintaining a fork of LunarG's gfxreconstruct repo, moving FRAME_BEGIN presents a massive maintenance risk. Altering where such a core API event is dispatched within the loop will likely introduce severe and complex merge conflicts whenever we try to sync upstream changes in the future.

Regarding the alternative proposal (starting capture at the first QueueSubmit): Unfortunately, this doesn't work well with RenderDoc. RenderDoc intercepts API calls as they happen; if we wait until QueueSubmit to call StartFrameCapture(), we completely bypass the command buffer recording phase (vkCmd...), so RenderDoc won't capture the actual contents of the frame. Additionally, the state loader also makes queue submits, meaning we'd still need an event to differentiate the state loading sequence from the actual frame submit.

Given our tight schedule and fork-maintenance requirements, I propose the following compromise:

  1. I will leave the code structurally as-is but add a comment clearly marking GFXR_REPLAY_EVENT_STATE_LOADING_COMPLETE as a temporary additive stopgap. This prevents it from becoming permanent technical debt.
  2. We log this FRAME_BEGIN issue with LunarG and ask them to fix it upstream.
  3. Once LunarG pushes the fix to their stable branch, we pull it, cleanly drop our temporary STATE_LOADING_COMPLETE event without painful merge conflicts, and update the plugin's logic.

I can push a quick commit to add the temporary note right now if this sounds like a good path forward.

@olehkuznetsov

olehkuznetsov commented Jul 9, 2026

Copy link
Copy Markdown

I agree that the first proposal (fixing FRAME_BEGIN so it doesn't include the setup state) is architecturally the correct solution. Conceptually, the state setup sequence injected by the trimmer shouldn't bleed into what we define as the workload of the first replayed frame.

However, since we are maintaining a fork of LunarG's gfxreconstruct repo, moving FRAME_BEGIN presents a massive maintenance risk. Altering where such a core API event is dispatched within the loop will likely introduce severe and complex merge conflicts whenever we try to sync upstream changes in the future.

Regarding the alternative proposal (starting capture at the first QueueSubmit): Unfortunately, this doesn't work well with RenderDoc. RenderDoc intercepts API calls as they happen; if we wait until QueueSubmit to call StartFrameCapture(), we completely bypass the command buffer recording phase (vkCmd...), so RenderDoc won't capture the actual contents of the frame. Additionally, the state loader also makes queue submits, meaning we'd still need an event to differentiate the state loading sequence from the actual frame submit.

Given our tight schedule and fork-maintenance requirements, I propose the following compromise:

  1. I will leave the code structurally as-is but add a comment clearly marking GFXR_REPLAY_EVENT_STATE_LOADING_COMPLETE as a temporary additive stopgap. This prevents it from becoming permanent technical debt.
  2. We log this FRAME_BEGIN issue with LunarG and ask them to fix it upstream.
  3. Once LunarG pushes the fix to their stable branch, we pull it, cleanly drop our temporary STATE_LOADING_COMPLETE event without painful merge conflicts, and update the plugin's logic.

I can push a quick commit to add the temporary note right now if this sounds like a good path forward.

We should just upstream FRAME_BEGIN fix.

For queue submit - I think it works a bit differently.

  1. You will not receive setup queue submit as events.
  2. There will be often command buffers which are recorded in setup phase and are using during frame, so, render doc should be able to handle it anyway. I think they track all commands before capture starts, but will show only relevant to frame.
    Have you tried the approach with QUEUE_SUBMIT event?

My expectation is you just need first queue submit event, after FRAME_BEGIN. It should work even without FRAME_BEGIN event fix.

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.

2 participants