Skip to content

sparse_strips: Move some code from vello_cpu to vello_common#1744

Merged
LaurenzV merged 9 commits into
mainfrom
laurenz/vello_hybrid_shift_part1
Jul 20, 2026
Merged

sparse_strips: Move some code from vello_cpu to vello_common#1744
LaurenzV merged 9 commits into
mainfrom
laurenz/vello_hybrid_shift_part1

Conversation

@LaurenzV

@LaurenzV LaurenzV commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

This is the first PR in a series of three (perhaps four) PRs that serve as a preparation for the Vello Hybrid rewrite.

This PR is easiest reviewed commit by commit, though there isn't that much to review in the first place. Apart from adjusting a few descriptions, it's mostly just moving some code around.

The first 7 commits were done by manually copy-pasting code into the right location. The last commit that fixes compiler issues were done with AI assistance.

PR train

  1. sparse_strips: Move some code from vello_cpu to vello_common #1744 — Move some code from vello_cpu to vello_common 👈
  2. sparse_strips: Add more new/refactored code into vello_common #1745 — Add more new/refactored code into vello_common
  3. vello_common: Generalize the command recorder abstraction and add more metadata #1746 — Generalize the command recorder abstraction and add more metadata
  4. sparse_strips: Introduce Padding type and streamline clip handling #1751 — Introduce Padding and streamline clip handling

Comment on lines +178 to +187
// This struct implements an additional piece of logic to make non-isolated clips work properly
// with filter layers. The root of all "evil" that requires us to implement this wrapper around
// [`crate::clip::ClipContext`] is that, as the user pushes new filter layers into the
// render context, we eagerly apply a shift to all subsequently rendered contents to ensure that
// everything necessary for correct filter rendering is guaranteed to be visible. However, since
// the clip stack eagerly generates strips for each clip path that is clipped to the original
// viewport, those generated clip paths cannot just be translated on demand to account for the
// source shift of the filter layer. Therefore, every time a new filter layer is pushed, we need
// to regenerate the clip context for that specific layer to ensure clips are applied correctly.
/// State for managing clip paths across multiple viewports.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This was slightly rewritten from the original doc comment.

Comment thread sparse_strips/vello_common/src/record.rs Outdated
@grebmeg

grebmeg commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Btw, it might be worth keeping this branch (or maybe main-vello-hybrid-filter-fix) as a consolidated branch so it's possible to review the entire change one more time in one place. PR train makes reviewing large changes much easier, but it also makes it harder to see how the whole implementation fits together. If you spot an issue later and the relevant PR has already been merged, it becomes more difficult to fix it or, in the worst case, it'd need a hotfix.

@LaurenzV
LaurenzV added this pull request to the merge queue Jul 20, 2026
Merged via the queue into main with commit 93162ef Jul 20, 2026
19 checks passed
@LaurenzV
LaurenzV deleted the laurenz/vello_hybrid_shift_part1 branch July 20, 2026 06:27
pull Bot pushed a commit to Mu-L/vello that referenced this pull request Jul 20, 2026
…bender#1745)

This PR is based on linebender#1744 and introduces some actual changes, once again
in preparation for the Vello Hybrid rewrite.

The first commit adds some utility types like `Offset` and `Size`, which
will layer on be used by Vello Hybrid (they are currently partially
duplicated there, but I will just remove them later on). In theory they
could just live in Vello Hybrid, but since we already have `RectU16` in
vello_common I figured this is the best place.

The second commit resolved a TODO and creates a new generic method that
allows generating fill/alpha-fill sequences from a slice of strips. We
also use this for the existing `strip_bbox` function now. I'm aware that
this will result in a slight slowdown since we will do the clipping even
though it isn't necessary to clip anything since we are just calculating
the bbox, but I think it's better to accept this cost for less code
duplication.

The third commit extracts all of the transforms we currently have into a
custom struct, so that, once again, they can more easily be used by
Vello Hybrid.

Fourth commit introduces a new `ViewportState` abstraction, that
abstracts all of the complexity of handling different viewport so that
Vello Hybrid can use this as well.

Fifth commit adds a way of querying whether an encoded paint has any
opacities directly.

### PR train

1. linebender#1744 — Move some code from `vello_cpu` to `vello_common`
2. linebender#1745 — Add more new/refactored code into `vello_common` 👈
3. linebender#1746 — Generalize the command recorder abstraction and add more
metadata
4. linebender#1751 — Introduce `Padding` and streamline clip handling
pull Bot pushed a commit to Mu-L/vello that referenced this pull request Jul 20, 2026
…e metadata (linebender#1746)

This PR is based on linebender#1745. It changes the semantics of the command
recorder, turning it into something more akin to a scene graph (we
should probably rename it in the future!).

Up until now, the command recorder was written in a way that is only
"useful" to Vello CPU. Most notably, normal layers would be folded into
their parent stream, and only filter layers had an explicit
representation as an independent unit. For Vello Hybrid, this is not a
suitable representation, because _all_ layers need to be represented
explicitly and be rendered independently from the other layers.

To achieve this goal, this PR implements some changes, split up into two
commits.

The first commit represents a refactor of the overall representation.
Most notably:

- It is generic over an unspecified draw type. We need this because, in
addition to normal path fills as used by Vello CPU, Vello Hybrid also
supports fast path rects, which have a different inner representation.
Therefore, the actual draw type need to be able to be specified by each
backend independently.
- Instead of only treating filter layers as having their own root
commands, now every kind of layer has their own command stream. Vello
CPU will internally still ensure that they are inlined, but the crucial
point is that this assumption is not baked into the generic
representation anymore, so Vello Hybrid can do something different here.
- Instead of having four commands "Fill`, "PushLayer", "FilterLayerFill"
and "PopLayer" , we represent the whole scene as a tree of nodes, where
each node represent a number of batched draw commands, followed by an
optional layer invocation. Basically, we interleave normal draws and
layer fills in a way such that they can be iterated over more easily.
The fact that we represent a batch of draw commands as a simple range of
draw commands instead of a flat array of inlined draw commands helped
tremendously when building the new Vello Hybrid scheduler. Also, all
draw commands now end up in a global buffer which we can reuse more
easily across frames. The only downside is one more layer of indirection
per batch for Vello CPU, which is completely negligible.
- Since each layer now only stores a `Vec<Node>`, which is likely to be
very small, I decided to remove the `VecPool` for this. I don't think
it's worth it trying to reuse those across frames.

The second commit ensures that we store some more metadata about the
scene, which is needed for Vello Hybrid. Yes, we do pay some additional
cost for Vello CPU here, but it's basically nothing.

### PR train

1. linebender#1744 — Move some code from `vello_cpu` to `vello_common`
2. linebender#1745 — Add more new/refactored code into `vello_common`
3. linebender#1746 — Generalize the command recorder abstraction and add more
metadata 👈
4. linebender#1751 — Introduce `Padding` and streamline clip handling
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