Skip to content

RenderStartup causes an additional frame of latency in rendering (aka pink screen part 2) #20756

@andriyDev

Description

@andriyDev

This is a followup to #20318. In #20595, we changed how our cameras render slightly to at least change the pink screen into a black screen, which makes the missing frame slightly less noticable.

I documented the cause in other words here, however I will rewrite it here to hopefully better explain the issue.


In order to render with a shader in one frame, these things need to happen in this order:

  1. Call asset_server.load("my_shader");
    1. This starts the task that will load the shader.
  2. The load task needs to complete.
    1. Shaders are generally cheap to load (especially with embedded assets), so I will assume this always happens.
  3. The handle_internal_asset_events system needs to run (this is scheduled in PreUpdate in the main world).
    1. This takes the shader asset from the load task and adds it to the ECS.
  4. The ExtractSchedule must run.
    1. This moves the shader asset from the main world to the render world
  5. The Render schedule must run.
    1. This first compiles the render pipelines (using the shaders), then runs your rendering system.
    2. Note that compiling a render pipeline takes time, but PipelineCache::block_on_render_pipeline allows your rendering system to wait for the pipeline to be ready. Blocking on the render pipeline only works if the shader assets are already in the render world.

In the current state, the order is:

  1. The first main world frame runs. Nothing happens.
    1. So far nothing rendering related has run, so no shader loads have even started.
    2. handle_internal_asset_events runs, but doesn't pick up any shader assets, since we never started any loads.
  2. As part of "extract" RenderStartup runs.
    1. It finally calls asset_server.load("my_shader");. For argument's sake, let's assume the load finishes instantly.
  3. The ExtractSchedule runs.
    1. There are no shader assets to move from the main world to the render world, since handle_internal_asset_events didn't add any shaders to the ECS.
  4. The Render schedule runs.
    1. We try to compile the render pipelines, but they are missing shader assets, so they can't compile!
    2. Rendering systems do nothing when calling PipelineCache::block_on_render_pipeline since the shader assets are missing.
    3. We render a black screen!
  5. The main world starts a new frame. From here, everything goes back to normal: the shader asset is added to the ECS, then gets moved to the render world, then the pipelines are compiled, blocked on, and rendered with.

To fix this, we need to either 1) run RenderStartup earlier -- e.g., #20407, or 2) have shaders live entirely in the render world (which eschews the entire asset system) -- which could be done as part of WESL changes maybe?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-AppBevy apps and pluginsA-ECSEntities, components, systems, and eventsA-RenderingDrawing game state to the screenA-WindowingPlatform-agnostic interface layer to run your app inD-ComplexQuite challenging from either a design or technical perspective. Ask for help!S-Needs-Design-DocThis issue or PR is particularly complex, and needs an approved design doc before it can be mergedX-ControversialThere is active debate or serious implications around merging this PR

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions