Skip to content

Conversation

JMS55
Copy link
Contributor

@JMS55 JMS55 commented Oct 19, 2025

Objective

  • Reduce boilerplate for render nodes, building on my experience writing SSAO, TAA, virtual geometry, Solari, etc
  • Provide the missing low-level render API helper:
    • High level - Material and FullscreenMaterial
    • Mid level - Phase stuff
    • Low level - Missing until now

Solution

  • Provide a new RenderTask trait to handle all the boilerplate you would otherwise have to write manually:
    • Checking GPU features/limits when setting up the plugin
    • Setting up a render graph node and edge ordering
    • Preparing and caching textures and buffers
    • Preparing and caching pipelines
    • Preparing and caching bind groups/layouts
    • Setting up wgpu compute/render passes and setting state between dispatches/draws
    • Inserting profiling spans

Testing

  • Did you test these changes? If so, how?
  • Are there any parts that need more testing?
  • How can other people (reviewers) test your changes? Is there anything specific they need to know?
  • If relevant, what platforms did you test these changes on, and are there any important ones you can't test?

Showcase

impl RenderTask for SolariLighting {
    type RenderNodeLabel = node::graph::SolariLightingNode;
    type RenderNodeSubGraph = Core3d;
    fn render_node_ordering() -> impl IntoRenderNodeArray {
        (
            Node3d::EndPrepasses,
            node::graph::SolariLightingNode,
            Node3d::EndMainPass,
        )
    }

    fn encode_commands(&self, mut encoder: RenderTaskEncoder, entity: Entity, world: &World) {
        let Some((
            solari_lighting_resources,
            view_target,
            view_prepass_textures,
            view_uniform_offset,
            previous_view_uniform_offset,
        )) = world.entity(entity).get_components::<(
            &SolariLightingResources,
            &ViewTarget,
            &ViewPrepassTextures,
            &ViewUniformOffset,
            &PreviousViewUniformOffset,
        )>()
        else {
            return;
        };

        let frame_count = world.resource::<FrameCount>();
        let frame_index = frame_count.0.wrapping_mul(5782582);

        let push_constants = &[frame_index, self.reset as u32];

        encoder
            .compute_pass("presample_light_tiles")
            .shader(load_embedded_asset!(world, "presample_light_tiles.wgsl"))
            .push_constants(push_constants)
            .dispatch_1d(LIGHT_TILE_BLOCKS as u32);
    }
}

This section is optional. If this PR does not include a visual change or does not add a new feature, you can delete this section.

  • Help others understand the result of this PR by showcasing your awesome work!
  • If this PR adds a new feature or public API, consider adding a brief pseudo-code snippet of it in action
  • If this PR includes a visual change, consider adding a screenshot, GIF, or video
    • If you want, you could even include a before/after comparison!
  • If the Migration Guide adequately covers the changes, you can delete this section

While a showcase should aim to be brief and digestible, you can use a toggleable section to save space on longer showcases:

Click to view showcase
println!("My super cool code.");

@JMS55 JMS55 added A-Rendering Drawing game state to the screen C-Code-Quality A section of code that is hard to understand or change C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes labels Oct 19, 2025
@torsteingrindvik
Copy link
Contributor

Is ordering always (before, myself, after)? If so is it enough to specify before and after?

@JMS55
Copy link
Contributor Author

JMS55 commented Oct 19, 2025

Is ordering always (before, myself, after)? If so is it enough to specify before and after?

I suppose yeah, but before/after can be more than 1 thing.

@atlv24
Copy link
Contributor

atlv24 commented Oct 19, 2025

I think @torsteingrindvik was suggesting having

    type AfterNodeLabel = Node3d::EndPrepasses;
    type RenderNodeLabel = node::graph::SolariLightingNode;
    type BeforeNodeLabel = Node3d::EndMainPass;
    
    // this is the same for all RenderTasks
    fn render_node_ordering() -> impl IntoRenderNodeArray {
        (
            Self::AfterNodeLabel,
            Self::RenderNodeLabel,
            Self::BeforeNodeLabel,
        )
    }

@JMS55
Copy link
Contributor Author

JMS55 commented Oct 19, 2025

No yeah I get the idea. I just don't think we can do that because you could want more than 1 thing before/after.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Code-Quality A section of code that is hard to understand or change C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants