Skip to content

Visual layer plan#1723

Draft
waywardmonkeys wants to merge 3 commits intolinebender:mainfrom
waywardmonkeys:visual-layer-plan
Draft

Visual layer plan#1723
waywardmonkeys wants to merge 3 commits intolinebender:mainfrom
waywardmonkeys:visual-layer-plan

Conversation

@waywardmonkeys
Copy link
Copy Markdown
Contributor

This PR introduces VisualLayerPlan as Masonry’s shared visual-layer model and uses it to carry explicit paint boundaries from masonry_core through host presentation.

The main outcome is that Masonry can now represent and preserve an ordered layer sequence like:

  1. Masonry scene content below
  2. a host-managed external surface slot
  3. Masonry scene content above

That gives us a cleaner path toward compositor-driven presentation, instead of flattening everything into one scene and treating external content as a special case.

This PR does not claim that the compositor model is finished.

In particular:

  • VisualLayerPlan is still a flat ordered plan, not a grouped/tree compositor model
  • the subduction path is an early host integration, not the final cross-platform presentation architecture
  • scene-layer caching / frame pacing / platform-native presenter choices re follow-up work

@waywardmonkeys waywardmonkeys force-pushed the visual-layer-plan branch 4 times, most recently from 7625468 to 8f61dd7 Compare April 12, 2026 14:19
@waywardmonkeys
Copy link
Copy Markdown
Contributor Author

This was done with assistance from Codex (gpt-5.4, high). But the overall design is mine. (But probably still evolving ...)

Copy link
Copy Markdown
Contributor

@PoignardAzur PoignardAzur left a comment

Choose a reason for hiding this comment

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

I'm going to be honest, I gave up halfway through subduction_presenter.rs, because at some point I don't even know if I'm giving feedback to Bruce or to some LLM, and this doesn't feel like a good use of my time.

Anyway, the guiding principle of Masonry is that we make a lot of effort to keep the code readable for complete beginners. This principle is relaxed for Masonry Winit because platform glue code is inherently messy, but even then, this PR does not remotely meet our standards.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's keep all the examples in masonry/examples/.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This one is here for now because parts of it are very specific to masonry_winit and with other stuff that I had locally, it was annoying to keep other things building ... but I'll move it before this lands.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This test file should be moved to masonry/src/tests/.

There's a few reasons we do a lot of tests in masonry instead of masonry_core. The main one is that masonry defines a lot of widgets that are useful for tests. For instance, PaintLeaf, TripleRow, OffsetBox and MixedTripleRow could trivially be replaced by SizedBox and Flex.

Overall, tests are supposed to be a kind of maintainer-only documentation explaining what we expect from the code. You shouldn't need to read the implementation of four custom widgets to get to read a test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If we didn't have to implement a bunch of empty methods for every widget, this would've been a lot easier as well.

But the things that it is testing aren't as easily done with SizedBox / Flex given that they make things less easily deterministic ..

But I'll move it after other things are resolved.

Comment on lines +18 to 21
#[cfg(not(target_arch = "wasm32"))]
use std::fs::File;
#[cfg(not(target_arch = "wasm32"))]
use std::time::UNIX_EPOCH;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These seem like drive-by changes? I don't think they're needed for this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

They were required to fix CI since with this, some stuff started getting compiled for Wasm in the existing CI that wasn't happening before.

They can probably be done in a separate PR at some point.

Copy link
Copy Markdown
Contributor

@PoignardAzur PoignardAzur Apr 12, 2026

Choose a reason for hiding this comment

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

Alright, so this file defines breathes in VisualLayerId, ExternalLayerKind, VisualLayerBoundary, VisualLayerKind, VisualLayer, SceneVisualLayer, ExternalVisualLayer, and VisualLayerPlan.

This is my problem with these AI-generated PRs. Even if all of the code is correct, they add a lot of API surface that you then need to learn and maintain.

Also, general comment: while this isn't documented anywhere (but it should be!), Masonry modules usually adhere to a coding style where all types are defined first, then implementations. This helps identify which types are composed of which other types, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Some of the are because I used to have support for actual child windows on Windows and macOS before, not just a single external layer. I've removed that though thinking I might add it back, but realistically, I'll probably never actually re-implement that within Masonry.

The problem here with these types isn't that it was AI generated, it is that at various points (over the last more than a week), this PR has been doing a lot of other things along the way that I removed.

Also, some parts of this are actually complex things to model and require some detail.

But the VisualLayerPlan is the actually important thing here and where most of the attention has gone.

Comment thread masonry_core/src/app/render_layers.rs Outdated
Comment on lines +74 to +75
/// Where this visual layer boundary originated.
pub boundary: VisualLayerBoundary,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We've had a discussion about AI-generated doc lately, where Raph posted a parody of AI doc. Reading a lot of doc in this file reminds me of Raph's parody; this line is a good example.

When we have a type named VisualLayer with a field named boundary of type VisualLayerBoundary, a doc that says "Its the visual layer boundary" is extremely unhelpful.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Would you rather the type be called Boundary?

It is fair to call out that the doc comment could use more work.

Or I guess we could mock the work that I'm doing instead of something productive.

Comment thread masonry_winit/src/app_driver.rs Outdated
Comment on lines +205 to +210
fn on_visual_layers(
&mut self,
window_id: WindowId,
ctx: &mut DriverCtx<'_, '_>,
layers: &VisualLayerPlan,
) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not super clear on how this is supposed to be used, from reading documentation.

Is the expectation that apps with custom layers will render them to wgpu from this method? Or just update them?

Also, on_visual_layers is a confusing name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is for letting a host inspect the frame without taking over presentation. I'll just remove it.

Comment on lines +62 to +72
pub trait SceneLayerRenderer {
/// Render the given scene layer into `target.view`.
fn render_scene_layer(
&mut self,
target: SceneLayerTarget<'_>,
layer: SceneVisualLayer<'_>,
) -> Result<(), BoxError>;
}

/// Realize host-owned external layers into the textures allocated by the subduction presenter.
pub trait ExternalLayerRenderer {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think at some point I'm going to put out an official moratorium on adding more traits to the Xilem codebase, because the trait inflation is getting way out of control.

I'm pretty sure these two could just be impl Fns.

Comment on lines +48 to +59
pub struct SceneLayerTarget<'a> {
/// Device used for rendering.
pub device: &'a wgpu::Device,
/// Queue used for uploads and submission.
pub queue: &'a wgpu::Queue,
/// Texture view owned by the compositor for this layer.
pub view: &'a wgpu::TextureView,
/// Output size in physical pixels.
pub output_size: winit::dpi::PhysicalSize<u32>,
/// Window scale factor used to convert logical layer geometry into pixels.
pub scale_factor: f64,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Okay, so this struct is exactly the same as ExternalLayerTarget, except without the format field. I suspect they could have been merged.

Comment on lines +164 to +165
/// Host-specific renderer for external layers with optional per-layer state.
pub trait ManagedExternalLayerRenderer {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh hey, a third trait!

layer: Layer,
}

trait ExternalLayerStateDriver<Layer, State> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh hey, a fourth trait!

@waywardmonkeys
Copy link
Copy Markdown
Contributor Author

I'm going to be honest, I gave up halfway through subduction_presenter.rs, because at some point I don't even know if I'm giving feedback to Bruce or to some LLM, and this doesn't feel like a good use of my time.

It is fair to give up in parts of that version of the presenter. I've done a massive simplification on it now that I've removed some other things and will probably never re-implement them within Masonry (like OS child windows and a form of native control integration).

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