Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rectangles #187

Open
raphlinus opened this issue Jul 29, 2022 · 1 comment
Open

Rectangles #187

raphlinus opened this issue Jul 29, 2022 · 1 comment

Comments

@raphlinus
Copy link
Contributor

Currently every draw object is associated with a full Bézier path. That'll be particularly wasteful when we have more draw objects that are images or glyphs drawn from a texture atlas. I'm implementing axis-aligned rectangles as a special case of geometry, and finding it useful to write the design down for references.

As usual, a change like this touches many stages of the pipeline. In addition to the changes listed below, there are places that make the assumption that the draw object index and path index are the same, and that will need to change (that's already something that

Encoding

The design is for axis-aligned rectangles. Therefore the "append fragment with transform" function needs to handle one special case: the transform is not axis-aligned, and the appended fragment contains rectangles. In that case, the rectangles need to be expanded to full paths.

(in the piet render context, this logic is simpler, as the transform is known at the time the draw command is issued, but we're not planning on retaining this)

Alternative considered: use parallelogram as the primitive rather than axis-aligned rectangle, so it's closed under general affine transform.

The encoding is as follows: the draw object tag gets an extra bit incidating rect or path. If it's a rect, the drawdata stream gets 4 f32's representing the coordinates.

(to be determined: many choices for bit encoding; it's already got a bunch of bit magic for making size calculations faster)

Alternative considered: separate stream for rectangle coordinate data. That would require another scalar in DrawMonoid.

Draw scan

No major change here except to incorporate size into scene_offset. (easiest way to do that is to have just one bit for rect, mask and shift to add it to size). Also obviously don't increment path_ix when rect bit is set.

Currently draw_leaf fetches the bounding box, but it looks like that's unnecessary and can be cleaned up.

Note that rectangles are not represented in the pathtag or path data stream, so the pathtag scan and coarse path rendering are not affected.

Binning

Binning is the main place the bbox is processed, as it's the place in the pipeline where the clip bbox is available.

The output rect is stored into draw_bbox_alloc. This will serve as the dimensions of the rectangle as well for downstream processing.

Discussion question: I'm tempted to have draw leaf compute the bbox (otherwise it would be output in path_coarse). If it's the same format, that format will need to change, as it's currently quantized to integers (so it can be operated on by atomics). If the format is changed (say, 8 bits of fraction), then binning can be completely unaffected.

Coarse raster

When the rect bit is set, don't reference the path data structure, rather do some special-case processing.

The interior of the rect is a solid, but tiles on the edge need to issue a Cmd_Rect, see below for more details on that.

Fine raster

One new command: Cmd_Rect. Rendering is by multiplication of half-planes antialiased by clamp (this should be about as fast as non-AA rendering).

Also note: the most natural encoding for rect coords is 4 f32's, but those could be more compact. Using f16's (tile-relative) would also be natural, but even u8 (with 1/16 pixel quantization) is doable.

@nigeltao
Copy link

nigeltao commented Apr 20, 2023

Alternative considered: use parallelogram as the primitive rather than axis-aligned rectangle, so it's closed under general affine transform.

The encoding is as follows: the draw object tag gets an extra bit incidating rect or path. If it's a rect, the drawdata stream gets 4 f32's representing the coordinates.

I might be mis-understanding the issue but a drive-by suggestion: if you can spend yet another bit, you could distinguish quadratic (4 x f32) Bezier-path from (4 x f32) rect/parallelogram from (4 x f32) ellipse as per https://nigeltao.github.io/blog/2021/three-points-define-ellipse.html

Or, without needing another bit (assuming a path vs rect bit), you could have linear (2 x f32), quadratic (4 x f32) and cubic (6 x f32) Beziers versus circle (2 x f32, although not closed under affine transformation), rect/parallelogram (4 x f32) and rounded-ish-rectangle (6 x f32, with 4 of those defining the 'skeleton' parallelogram and the last 1 or 2 'coordinates' being some sort of squircley rounded-ness parameter and/or perhaps how many 'quarters' of the implicit ellipse you take).

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

No branches or pull requests

2 participants