Express quad shader coordinates in a consistent coordinate space
Categories
(Core :: Graphics: WebRender, task, P3)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox149 | --- | fixed |
People
(Reporter: nical, Assigned: nical)
References
(Blocks 1 open bug)
Details
Attachments
(8 files, 1 obsolete file)
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
Bug 1998432 - Add a GpuBufferBuilderF/I convenience method to push a single sequence of blocks. r=gw
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review |
Problem/situation
At the moment, quad segments are expressed either in layout or device space which is a source of complexity and confusion:
- quad segments drawn into an intermediate target use layout coordinates,
- quad segments drawn into the destination target using the direct strategy use layout space,
- quad segments drawn into the destination target using nine-patch or tiling strategies use device space.
Nine-patches requires the local to device transform to be axis aligned. Tiled quads don't seem to explicitly require it but accidentally do (See this assertion which mentions nine-patches but actually is in the tiled code path, I suspect that rotated tiled quads currently just crash).
The pattern is always specified in a sort of layout space that is relative to the primitive itself.
To make things work when quad segments are drawn using device space with a pattern specified in layout space we provide to the shader an optional device -> layout transform which is assumed to always be at most a scale and offset.
Currently this means that the same primitive is sometimes written twice in the gpu buffer (one with and one without the transform to fix pattern coordinates).
Quad shaders need to do at least some computation in a coordinate space that is appropriate for sizing and aligning intermediate render tasks. In general it is device space (see get_surface_rect).
It is conceptually simpler if decomposition happens in device space, because we can ensure that snapping the segments is done consistently with the way intermediate render tasks are sized. This enforces decomposition to happen in an axis-aligned coordinate system, which is fine most of the time and not optimal in other cases.
I also want to add a new clipping method (clip paths) that requires a decomposition in device space.
Aspirations
Ideally we'd express quad coordinates in a coordinate space that is a step between layout and device space (I would call it "raster space" if the name wasn't already taken, let's call it "quad space"). It would in general map device space exactly, but would also give us the flexibility to, for example, decompose a rotated primitive before applying the rotation (if we so chose).
The primitive data in the gpu buffer could contain coordinates in quad space as well as a transform from quad space to device space and a transform from quad space to layout space for patterns.
We probably need to support full 2d transforms for the patterns. I don't see how we can do an axis-aligned decomposition of a rotated primitive otherwise.
| Assignee | ||
Comment 2•6 months ago
|
||
Updated•6 months ago
|
| Assignee | ||
Comment 3•6 months ago
|
||
| Assignee | ||
Comment 4•6 months ago
|
||
... At least if the transformation between the destination node and the common ancestor is invertible.
This is needed to express some raster-to-clip transforms.
| Assignee | ||
Comment 5•6 months ago
|
||
After this patch the rule becomes:
- If a quad primitive has a simple transform (scale+offset), the transform
is applied to the CPU and the shader receives device space coordinates and
an identity transform. - If a quad primitve has a complex transform, the transform is applied in
the shader which receives layout coordinates.
This removes mismatches that were happening between the transform performed on the CPU
and the one applied on the GPU, which were causing glitches. It also simplifies the
mental model.
| Assignee | ||
Comment 6•6 months ago
|
||
// Let's us write:
let address = gpu_buffer.push(&foo);
// equivalent to:
let mut writer = gpu_buffer.write(Foo::NUM_BLOCKS);
foo.write(&mut writer);
let address = writer.finish();
| Assignee | ||
Comment 7•6 months ago
|
||
I am going to use this type for things that are similar but not limited to specifying AA edges.
| Assignee | ||
Comment 8•6 months ago
|
||
Now that non-axis-aligned primitives are consistently projected to device space in the prepare phase,
we can guarantee that indrect quads cover their render tasks exactly.
This is done by rounding the coordinates of non-aa sides and making setting the task rect to the primitive's
tight clip rect in device space.
Since we do this for indrect quads we have to also do it for other rendering strategies, to prevent cracks
between side-by-side primitves without anti-aliasing.
| Assignee | ||
Comment 9•6 months ago
|
||
Primitive space clips used to rely directly on the primitive's blocks with an additional prim->clip transform so to adjust the pattern coordinates of the clip.
This no longer works if the primitve is pre-transformed to device space because the device->clip transform that would be required to fix up the pattern coordinate sof the clip cannot always be expressed.
A example of the problem is with when the primitive and the clip use the same spatial node, which is under a (flattened) perspective transform. The prim/clip -> device transform can be expressed, the prim->clip transform as well (indentity), but the inverse device->clip primitive typically can't with flattened perspective.
A solution could be to produce geometry for the clip relative to its own spatial node. This way clips and regular primitives could work exactly the same way.
However a requirement for the clip is that it entirely covers the primitive. This was conveniently achieved by reusing exactly the geometry of the primitive for the clip, but with geometry psositioned in the clip's space we would have to project the primitive's bounds into the clip's space and inflate the clip until it covers the primitive.
A simpler solution (this patch) is to no longer reuse the primitive's gpu block for the clip (since they may have been pre-transformed), and instead build new clip gpu blocks from the primitive's local coordinates.
| Assignee | ||
Updated•6 months ago
|
Comment 10•6 months ago
|
||
| Assignee | ||
Comment 11•6 months ago
|
||
This reflects a change that happened in an previous patch in this series.
Comment 12•6 months ago
|
||
| bugherder | ||
Comment 13•6 months ago
|
||
Comment 14•6 months ago
|
||
| bugherder | ||
Comment 15•6 months ago
|
||
Updated•6 months ago
|
Comment 16•6 months ago
|
||
Comment 18•6 months ago
|
||
Comment 19•6 months ago
|
||
| bugherder | ||
| Assignee | ||
Updated•6 months ago
|
| Assignee | ||
Updated•6 months ago
|
Updated•6 months ago
|
Updated•5 months ago
|
Description
•