Commit Graph

129 Commits

Author SHA1 Message Date
Elias Naur ce116abded op/clip: specify path for stroked Rects
Fixes: https://todo.sr.ht/~eliasnaur/gio/358
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-02-10 19:01:08 +01:00
Elias Naur 65199a2274 op,internal/ops: support CallOps without macros
A recorded macro is prefixed with an internal macro op that stores
the end of the macro. The end is used to efficiently skip the macro
when not calling it. The call a macro, the CallOp stores the start
position of the macro.

To support seamless wrapping of Ops lists, this change removes the
dependency on the macro op prefix from CallOp. Internal code can
now call an Ops like this:

    var ops op.Ops
    var wrapper op.Ops

    ops.AddCall(&wrapper.Internal, &ops.Internal, ops.PC{}, ops.PCFor(&ops.Internal))

References: https://todo.sr.ht/~eliasnaur/gio/318
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-01-20 09:56:30 +01:00
Pierre Curto 9a2fee1c0e op, internal/ops: cleanups
Remove unnecessary fill when starting a recording in op.Record.
Have the exact number of possible stack kinds in ops.Ops.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2022-01-18 15:49:43 +01:00
Pierre Curto 2ce9ad36af clip: check Path ops are not mixed with others
Multiple operations Op, such as clip.Path, cannot
be interleaved with other ops. This patch adds a
mechanism to ensure that is the case by starting
multi ops with ops.BeginMulti and ending them with
ops.EndMulti while operations are written to op.Ops
with ops.WriteMulti.
This mechanism is applied to clip.Path.

Fixes: https://todo.sr.ht/~eliasnaur/gio/336
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2022-01-15 19:16:07 +01:00
Pierre Curto 11bb86166a op/clip: automatically close Path in Outlines
Unclosed path segments in Path will be automatically
closed by a line.

Fixes: https://todo.sr.ht/~eliasnaur/gio/320
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-12-21 10:13:20 +01:00
Elias Naur 6534639276 io/pointer,op/clip: remove clip.Circle, pointer.Rect, pointer.Ellipse
They've been deprecated for a while, and gio-x is updated to not use
them.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-12-20 16:23:16 +01:00
Pierre Curto 872b4ba41b op/clip: fix Path open state
If a Move/MoveTo did not move the pen, the Path
was still set as open.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-12-02 11:50:01 +01:00
Pierre Curto 227c5a132b op/clip: don't panic when Path is used without an initial MoveTo
A Path initialized with Begin should be ready to use with its pen at (0,
0). Make it so.

Updates gio#311

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-11-26 22:34:25 +01:00
Pierre Curto 5fd4ecb011 clip: add Path method to Ellipse
Useful when drawing ellipses with Stroke.
Also, this makes it consistent with the other clip operations.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-11-26 22:23:03 +01:00
Pierre Curto 6bfd980044 op/clip: don't panic on zero-sized Ellipse
When the rectangle used in an Ellipse has no width
or height, the path would panic with "path not closed".
Use an empty rectangle path in that case instead.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-11-16 15:50:53 +01:00
Pierre Curto bcf3ff77ff op/paint: remove unnecessary check in ImageOp
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-11-10 17:31:50 +01:00
Pierre Curto 3f25a49c75 clip: add Path method to Rect
Useful when drawing non-rounded rectangles with Stroke.
Also, this makes it consistent with RRect and Circle which
also have a Path method.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-11-07 11:02:52 +01:00
Elias Naur 29cea1db49 io/pointer,io/router: replace AreaOp with clip.Op
Pointer hit areas and paint clip areas are separate concepts, but
similar enough to warrant merging. This change replaces pointer hit
areas with clip areas, so Gio is left with just one area concept (in
package op/clip).

The reason for separating the concepts in the original Gio release was
because of my being unsure general path/stroke hit areas would ever be
implemented, let alone efficient.

This change represents a change of mind, in the sense that it's better
to have an incomplete API than two separate area concepts.

Leave the deprecated pointer.Rect, pointer.Ellipse for temporary
backwards compatibility.

This is an API change. Most existing programs should continue to build
with this change, but may have to adjust to having all clip.Ops participate
in InputOp hit areas.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-11-03 14:12:31 +01:00
Elias Naur 28fc08a508 op/clip: introduce axis-aligned Ellipse shape
And deprecate (but not yet remove) Circle.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-11-03 14:12:31 +01:00
Elias Naur 563eb60382 op: remove op.Save
op.Save, op.SaveStack were compatibility stop-gaps.

API change. Most op.Save/Loads can safely be removed altogether, or
replaced with

trans := op.Offset(f32.Pt(0, 0).Push(gtx.Ops)
...
trans.Pop()
cl := clip.Rect(image.Rect(-1e6, -1e6, 1e6, 1e6)).Push(gtx.Ops)
...
cl.Pop()

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-26 12:13:11 +02:00
Elias Naur e14e33b87e op/clip: remove Op.Add
The Add method was a compatibility stop-gap.

API change. Use clip.Op.Push and Pop the return value to explicitly mark
the region affected by the clip operation.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-26 12:13:11 +02:00
Elias Naur 0048f7be1d internal/ops: hide Ops methods by converting them to package functions
Ops is in the internal package ops, but external clients can reach its
method through op.Ops.Internal. Hide them by converting them to internal
package functions.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-12 14:50:15 +02:00
Elias Naur bd1ef92dc4 op/clip: remove complex stroke support
In a discussion with Raph Levien, the author of our compute renderer
implementation, it became clear to me that it's not at all certain that
complex strokes will ever be efficiently supported by a GPU renderer.

At the same time, the machinery for converting a complex stroke to a
GPU-friendly outline has a significant maintenance cost. Further, it is
surprising to users that complex strokes are significantly slower and
allocate memory.

This change removes support for complex strokes, leaving only
round-capped, round-joined strokes supported by the compute renderer.
The default renderer still converts all strokes to outline, but it also
caches the result.

This is an API change. The complex stroke conversion code has been moved
to the external gioui.org/x/stroke package, with a similar API.

Updats gio#282 (Inkeliz brought up the allocation issue)

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-08 18:10:47 +02:00
Elias Naur 391725b9d0 op: move Ops internal methods and state to internal package ops
Merge package opconsts into ops as well; it only existed to break
import cycles.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-08 17:21:56 +02:00
Elias Naur 936c266b03 all: [API] split operation stack into per-state stacks
The op.Save and Load methods exist to support the need for
transformation, clip, pointer area state to behave as stacks. For
example, layout needs to apply an offset to its children but not
subsequent operations.

Before this change, op.Save and Load were used to save and restore the
state:

    ops := new(op.Ops)
    // Save state.
    state := op.Save(ops)
    // Apply offset.
    op.Offset(...).Add(ops)
    // Draw with offset applied.
    draw(ops)
    // Restore state.
    state.Load()

A drawback with the op.Save mechanism is that there is no direct
connection between the state change and the saving and loading of state.
This causes confusion as to when a Save/Load is needed and who is
responsible for performing them, which leads to subtle bugs and over-use
of Save/Loads.

This change gets rid of the general state stack and replaces it with
per-state stacks. There is now a stack for transformation, clip, pointer
areas, and they can only be restored by the code pushing state to them.
The example above now becomes:

    ops := new(op.Ops)
    // Push offset to the transformation stack.
    stack := op.Offset(...).Push(ops)
    // Draw with offset applied.
    draw(ops)
    // Restore state.
    stack.Pop()

For convenience, transformation also be Add'ed if the stack operation is
not required.

Simple state such as the current material no longer has a way to be
restored; it is assumed the client of a PaintOp adds their desired
material operation before it.

API change: replace op.Save/Load with explicit Push/Pop scopes for
op.TransformOps, pointer.AreaOps, clip.Ops.

To ease porting, this change retains a version of op.Save/Load that
saves and restores the transformation and clip stacks. It also retains
an Add method for clip.Op.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-08 17:21:56 +02:00
Elias Naur 62daadb37c op/clip: add absolute Path.ArcTo for completeness
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-07 17:36:36 +02:00
Elias Naur 414be0a0b3 gpu: Merge GPU.Collect and GPU.Frame
There's no meaningful reason to have them separate. The intention was to
enable rendering concurrent with other processing, but that's gaining
framerate at the expense of input latency and complicating ImageOp
semantics.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-24 08:30:52 +02:00
Petr Karmashev 1efe68c154 op/paint: remove duplicate word
Signed-off-by: Petr Karmashev <smonkl@bk.ru>
2021-08-04 12:58:05 +02:00
Elias Naur 5197f637a7 gpu: [compute] compute and store clipping path hashes during construction
The hash of the clipping paths that affect drawing operations are computed
and used to quickly determine that two operations are not equal, the
most likely outcome of a comparison.

However, for paths that are constructed once and cached computing the
hash at every frame is wasteful. This is especially true for text, which
is both cached and also among the largest paths in a frame.

This change moves the hashing to op/clip.Path construction time, and
stores the hash in the ops list so it won't be re-computed at every use.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur 75c9736708 op/paint: skip zero images
Updates gio#235

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-06-16 12:01:42 +02:00
Inkeliz b4e6d3efba internal/stroke, op/clip: remove unused variables
Fixes gio#233

Signed-off-by: Inkeliz <inkeliz@inkeliz.com>
2021-06-07 17:02:48 +02:00
Elias Naur 06ce077436 op/clip: compute bounds during Path build
The current renderer transforms and processes paths before sending them
to the GPU. It can compute bounds during processing.

The new renderer passes paths verbatim to the GPU, but needs the bounds
for constructing clip bounds.

This change computes the bounds during construction, so it is available
at use. As a bonus for storing the bounds with the path, path caches
(such as for storing text fragments) automatically reuse the bounds
calculations as well.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-04-27 16:49:06 +02:00
Elias Naur bc2c3db43e op/clip,gpu: move approximation of complex strokes to op/clip.Op.Add
Before this change, the two renderers both had special case code for
approximating strokes they don't support natively. This change moves
that conversion to clip.Op.Add, for several reasons:

- The compute renderer no longer need fallback logic and caches for
  strokes it doesn't support.
- The approximation logic is slow. Moving it to clip.Op.Add will not
  speed it up, but will make the cost easier to spot in profiles. Until all
  strokes are supported natively, users can use macros to cache
  expensive strokes.
- Reduced garbage: Op.Add takes an op.Ops anyway, and can use that for
  storing the approximated stroke outline.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-23 19:37:45 +01:00
Elias Naur 7825bda8f8 internal/stroke,op/clip: don't import op/clip from internal/stroke
To avoid an import cycle in a future change, internal/stroke can no
longer import op/clip. Move required op/clip functionality to
internal/stroke and duplicate the remaining types.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-23 15:28:52 +01:00
Elias Naur f9cf6ff20a op/clip: separate function for approximating arcs with quadratic curves
Both Path.Arc and the internal stroke package needs to support arcs;
this change isolates the approximation computation into a function we
can move to internal/stroke in a follow-up.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-23 15:01:00 +01:00
Elias Naur 13da40f601 gpu,op/clip: [compute] get rid of stroke vs fill flags
The fill mode is now controlled by a SetFillMode command, not by flags
on each path segment and fill command.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-19 21:46:31 +01:00
pierre ac800a9d8f op/clip: optimize zero corner radius in RRect if pixel-aligned
Signed-off-by: pierre <pierre.curto@gmail.com>
2021-03-16 19:00:47 +01:00
Egon Elbre 9cb9e67a8e op/clip: remove Border
Border can be expressed in-terms of clip.Stroke:

  clip.Stroke{
      Path: clip.UniformRRect(r, rr).Ops(ops),
      Style: clip.StrokeStyle{Width: width},
  }.Add(ops)

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2021-03-14 13:28:21 +01:00
Egon Elbre fecfbbb050 op/clip: expose Circle.Path and RRect.Path.
These can be nicely used together with clip.Stroke.

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2021-03-14 13:28:21 +01:00
Egon Elbre d994d092ae op/clip: use absolute coordinates in RRect
This avoids issues with floating point drift.

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2021-03-14 10:10:00 +01:00
Egon Elbre ee8e267d22 op/clip: add Circle and Path.CubeTo
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2021-03-14 10:08:50 +01:00
Elias Naur 2b21b48a7c gpu,gpu/shaders: revert attempt to fix path gaps
This is effectively a revert of [0], reintroducing the path gaps
described in [1]. A follow-up change will implement another attempt.

[0] https://gioui.org/commit/2feec23561cd84d6b8ddbab84a202df66b123208
[1] https://github.com/linebender/piet-gpu/issues/62

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-13 15:23:25 +01:00
Egon Elbre 65a2410bb9 op/clip: ensure that roundRect is always closed
Floating point error may accumulate and the round rect may not
necessarily close up entirely. Add an additional "Close" to ensure
it's properly closed.

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2021-03-13 13:49:59 +02:00
Elias Naur c5fb759aef op/clip: make RoundCap and RoundJoin the default stroke style
There's an argument that rounded caps and joins are the simplest stroke,
in that it can be defined to cover all pixels within lineWidth distance
from the supporting path.

However, the more important reason is that the compute renderer natively
supports this stroke style (without dashes), and users that don't care
(much) about the particular stroke style should get the efficient
implementation. A good example is op/clip.Border that strokes a closed
path, where the StrokeCap is irrelevant.

This is a (subtle) API change. If you have code that relies on the
default values of clip.StrokeStyle you may want to set Cap and Join
explicitly. See the test changes for examples. On the other hand, you
will get much better performance from the default Cap and Join values
once the compute renderer becomes the default.

Disablethe TestPaintClippedBorder test; dashes round-capped,
round-joined strokes doesn't seem to work correctly.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-12 12:19:39 +01:00
Elias Naur 9e79cee447 op/clip,gpu,internal/scene: encode cubic bézier curves natively
The compute renderer supports cubic curves, so encode them as such.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-11 18:54:12 +01:00
Elias Naur f1ae923a89 gpu,op/clip: encode lines as compute line commands, not quads
The new renderer supports lines natively; encode them as such and
convert them to a quadratic beziér.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-11 18:54:12 +01:00
Elias Naur a369c408f9 gpu: [compute] skip encoding roundtrip for path data
Since clip.Path now encodes paths in the format expected by
elements.comp, use that data directly instead of a roundtrip through
drawOps.buildVerts.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-11 18:54:12 +01:00
Elias Naur eb9bf60b09 gpu,internal/ops: decode scene commands directly, not through quads
We're about to let clip.Path use more of the compute renderer features
(lines, cubic béziers). This change prepares the gpu package for reading
one of several commands types, not just the quadratic béziers of before.

The old Quad type is still the basis for the stroking algorithms, but
this change moves it into package gpu which is the only user.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-11 18:54:12 +01:00
Elias Naur 07572387e3 internal/ops: switch quad encoding to compute format
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-11 18:54:12 +01:00
Elias Naur b8bdb96d35 op/clip,gpu,internal/opconst: remove quad count from Path op
The check for path segments in gpu is redundant; clip.Op.Add doesn't add
the Path op if there were no segments.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-11 18:19:31 +01:00
Elias Naur 884e7d27e2 op/clip: don't accept open Paths for Outline
Outline represents a clipping operations that clips all drawing outside
a closed path. Before this change, paths not closed we're patched up by
adding an implicit line from the endpoint to the beginning.

These fixups are inefficient for a rare case, but acceptable because the
old renderer post-processes all paths anyway. However, the new compute
renderer don't need post-processing in most cases, making fixups too
expensive.

Given that clipping to an open path is fundamentally undefined and that
implicit fixup with a closing line segment is merely a way to force the
clip to be well-defined, this change adds a panic to Outline for Paths
that are not closed.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-11 08:57:27 +01:00
Elias Naur cd47a158a2 op/clip: move Rect to shapes.go
It's a specialized shape like the others.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-19 20:31:29 +01:00
Chris Waldon d93874005c op/clip: document dimensions of Border.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2021-01-19 20:30:51 +01:00
Elias Naur d6886737a5 op: change Defer to only restore transformation state
It turns out restoring all operation state from the moment Defer
is executed is too much; for example, a right-click pop-up needs
the transformation, but not the current clip.

Change Defer to only restore the transformation, and reset all
other state.

Other combinations may be needed in future; we'll deal with them then,
possibly by exposing the load state mask.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-19 20:04:30 +01:00
Elias Naur f86703e4b0 op: introduce Defer for deferring CallOps
Updates gio#164

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-14 15:53:49 +01:00