Commit Graph

91 Commits

Author SHA1 Message Date
Elias Naur 62a8b80c81 internal/ops,gpu: remove transform fields from ops.Key
The transformation information in ops.Key is a layer violation.
Introduce a key type specific to package gpu and use that instead.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-19 16:37:06 +02:00
Elias Naur 9b5e9ae607 gpu/internal/opengl: restore BeginFrame state in EndFrame
To ease the integration with foreign OpenGL contexts, carefully save the
context state before rendering a frame and restore it afterwards. Gio
rendering can then be mixed with OpenGL code that expects exclusive
control over context state.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-06-11 21:02:18 +02:00
Elias Naur 39775f555a gp/internal/opengl: support sRGB emulation for embedded content
Programs such as gio-example/glfw rely on Gio drawing blending with
the framebuffer background. This change makes it so when sRGB emulation
is active.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-05-16 18:17:00 +02:00
Elias Naur 21c319ace5 gpu/internal/opengl,internal: move sRGB emulation to OpenGL driver
There is only one driver but several backends (EGL, WebGL).

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-05-16 10:44:45 +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 0a4b6549da internal/stroke,gpu: move stroking of path data to package internal/strokg
Pure refactor, preparing for use in op/clip.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-23 15:42:43 +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 8c8d1dc16f internal/stroke,gpu: create internal package for stroke to path conversion
Complex strokes are not yet supported in either of the current renderers,
so they are converted to filled outlines in package gpu.

We're about to move that complexity up to the op/clip package, so we're
going to need the converter available from outside package gpu. This
change extracts the conversion code and related types to the separate,
internal package stroke.

No functional changes; a follow-up moves the stroke conversion.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-23 12:35:41 +01:00
Elias Naur 1dde94d8dd gpu: [compute] use support for simple strokes
In the old renderer, all strokes are converted to filled paths. The new
renderer can draw simple strokes natively. Do that, and avoid the costly
conversions.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-19 21:46:32 +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
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
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 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 2328ddfeca internal/byteslice: rename package unsafe
All functions left in the old package unsafe were provided byte slice
views of other types. Rename the package accordingly and avoid a name
clash with the standard library package unsafe.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-11 11:27:02 +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 a722768da9 gpu/internal/opengl: rename and make internal the OpenGL driver
It is no longer necessary for outside users of package gpu to explicitly
initialize a specific driver. The Direct3D driver is already internal,
this moves the OpenGL driver internally as well. The rename to opengl is
to avoid the name clash with the low-level "gioui.org/internal/glimpl"
package that we're about to rename.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-06 14:27:44 +01:00
Elias Naur c799452c57 gpu/internal/driver: rename gpu/backend
There are no longer any importers of package backend outside of
gioui.org/gpu. Move it internally, and rename it to the slightly more
specific "driver" while we're at it.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-06 14:27:34 +01:00
Elias Naur 18a6dcf571 gpu/internal/d3d11: make the Direct3D backend internal to package gpu
The package app/internal/d3d11 now contains only the GPU backend on
Direct3D. Move it below package gpu to reflect that.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-06 14:26:47 +01:00
Elias Naur 8ff6546285 gpu,gpu/backend: implement generic backend.NewDevice
NewDevice creates a Device given an API, which is the necessary GPU
resources for a backend.

Convert gpu.New to take an API instead of a backend.Device directly.

In turn, this frees us to later unexport the backend package along with
the backend implementations (for now just gioui.org/gpu/gl for OpenGL).
It also allows programs that embed Gio (such as gioui.org/example/glfw)
to freely choose a backend, not just OpenGL.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-06 14:24:09 +01:00
Elias Naur 840b9ffa9b gpu/backend,gpu,app/internal/d3d11: move device state to backend
We'd like to allow Gio to share a Direct3D context with an embedding
program like the GLFW example does for OpenGL. To do that, d3d11.Device
needs to carry only the minimal information needed (ID3D11Device).

This change moves the caches of ID3D11DepthStencilState and
ID3D11BlendState from from d3d11.Device to d3d11.Backend. It also adds a
Release method for freeing them.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-06 14:21:51 +01:00
Elias Naur 25a19481e3 gpu,gpu/backend: don't assume constant output framebuffer
Return the output framebuffer from BeginFrame, to make it clear that
it may change between frames. Delete CurrentFramebuffer which is no
longer needed.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-02 20:43:59 +01:00
Elias Naur d8b29e3420 gpu: replace toRectF with layout.FRect
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-02-08 16:07:13 +01:00
Elias Naur 84b586ae6c gpu: don't automatically clear screen before rendering
Gio UI may be overlaid on top of custom graphics such as in the glfw example.
That will only work if Gio doesn't clear the screen (to white).

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-22 18:33:34 +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 f7902f299b op: implement StackOp in terms of general save/load of state
Push/Pop only allows saving and restoring operation state in a
stack-like manner. We're going to need restoring arbitrary state
for implementing deferred operations.

Generalize state save/restore and implement Push and Pop on top of
that.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-12 20:53:25 +01:00
Elias Naur bb9252f9d4 gpu: cache path data for compute
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-02 20:18:05 +01:00
Elias Naur 79016bcc4a gpu: close outline paths if not already closed
The new compute renderer is much less tolerant of discontinuous paths.
In particular, it requires that clip outlines form a closed loop.

Fixes TestPaintArc when GIORENDERER=forcecompute.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-02 12:40:54 +01:00
Elias Naur d23514fd58 gpu: add compute implementation
The old renderer is still the default, so the new compute renderer will only be
used in the rare case the old renderer is not supported but the new is. That
happens on the Samsung J2 Prime and Moto C Android phones. Or set the
GIORENDERER environment variable to "forcecompute" to disable the old renderer:

$ GIORENDERER=forcecompute go run ...

Missing features:
- Gradients are not supported yet, and render as a solid color.
- Draw timers are not added, and profile.Events are not emitted.
- Stroked paths may in some cases appear corrupted because their clip
  outlines are not continuous when generated by Gio. Sebastien is
  working on a fix.
- The new renderer shares most CPU-side logic with the old renderer,
  resulting in several inefficient conversion steps between the old
  operations representation and the new. This is slower, but minimizes
  divergence in features and bugs between the two renderers.

Roadmap:
- The compute renderer supports features that Gio does not yet
exploit: stroked paths with round caps, transformations, lines,
cubic beziér curves.
- More stroke styles and maybe dashed strokes natively in shaders.
- Metal and Direct3D ports.

The most important feature is porting the renderer to run on the CPU. A
CPU renderer will both support Gio on devices with insufficient GPU
support, and allow us to remove the old renderer. Two renderers is twice
the maintenance but the feature set of the weakest implementation.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-12-31 17:21:35 +01:00
Elias Naur 6f2a98c667 gpu: make GPU an interface to prepare for second implementation
While here, merge BeginFrame and EndFrame; the split was done for
performance reasons, yet never measured.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-12-31 17:21:35 +01:00
Elias Naur bfe2d04c60 gpu,app,internal/glimpl: update GL backend for the compute renderer
Modern graphics APIs have immutable objects, with mutable data. For example,
a texture's dimensions are immutable, while the texture contents is not.
Change the GPU API abstraction to match.

Clearing a Texture is convenient to do with a plain []byte. Generalize
Texture.Upload to take a plain byte slice and introduce a helper function for
uploading *image.RGBA data.

Add TextureFormatRGBA8 a format for the linear RGB colorspace.

Add OpenGL ES 3.1 functions for compute programs.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-12-31 17:21:35 +01:00
Elias Naur 7d24b790a2 gpu: add and track fields needed by the compute renderer
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-12-31 17:21:35 +01:00
Elias Naur 00c4a53036 gpu: move path cache updates into drawOps.collect
The new compute backend shares drawOps but not GPU.Collect. This
change moves the common path cache code to drawOps.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-12-19 15:43:51 +01:00
Sebastien Binet e71bf13c9a gpu,op/clip: implement dashed stroked paths
Signed-off-by: Sebastien Binet <s@sbinet.org>
2020-12-09 11:23:13 +01:00
Sebastien Binet be89f8b945 all: introduce Outline and Stroke builders
This CL introduces 2 new path builders:
- Outline which takes a PathSpec to be outlined
- Stroke which takes a PathSpec and a stroke style, to stroke a path.

typically, code like this:

  var p clip.Path
  ...
  p.Outline().Add(o)

should be replaced with:

  var p clip.Path
  ...
  clip.Outline{Path: p.End()}.Op().Add(o)

similarly, stroking should be modified from:

  var p clip.Path
  ...
  p.Stroke(width, clip.StrokeStyle{...}).Add(o)

to:

  var p clip.Path
  ...
  clip.Stroke{Path: p.End(), Style: clip.StrokeStyle{Width:...}}.Op().Add(o)

here are tentative 'rf' scripts (see rsc.io/rf for more details):

  ```
  ex {
  	import "gioui.org/op";
  	import "gioui.org/op/clip";

  	var p clip.Path;
  	var o *op.Ops;

  	p.Outline().Add(o) -> clip.Outline{Path:p.End()}.Op().Add(o);
  }

  ex {
  	import "gioui.org/op";
  	import "gioui.org/op/clip";

  	var o *op.Ops;
  	var p clip.Path;
  	var sty clip.StrokeStyle;
  	var width float32;

  	p.Stroke(width, sty).Add(o) ->   \
	    clip.Stroke{                 \
		Path:p.End(),            \
		Style: clip.StrokeStyle{ \
		    Width: width,        \
	    }}.Op().Add(o);
  }
  ```

Signed-off-by: Sebastien Binet <s@sbinet.org>
2020-12-09 09:44:15 +01:00
Egon Elbre 21ef492cc9 all: use color.NRGBA in public API
color.RGBA has two problems with regards to using it.

First the color values need to be premultiplied, whereas most APIs
have non-premultiplied values. This is mainly to preserve color components
with low alpha values.

Second there are two ways to premultiply with sRGB. One is to premultiply
after sRGB conversion, the other is before. This makes using the API more
confusing.

Using color.NRGBA in sRGB makes it align with CSS.e

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2020-11-19 11:30:11 +01:00
Sebastien Binet 7eb32360e5 gpu,op/clip: implement stroked paths with miter joins
Signed-off-by: Sebastien Binet <s@sbinet.org>
2020-11-11 16:14:49 +01:00
Elias Naur 7de8ce51a5 gpu: fix off-by-a-half clipping
I don't know why the 1/2 factor is there, but it leads to images being
rendered with a 0.5 pixel offset.

Remove the other useless checks while here: clipping 1px images shouldn't
be a problem and the destination rectangle is always non-zero (otherwise
it wouldn't be rendered).

Update the reference images that are subtly changed because of this fix.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-11-11 15:14:39 +01:00
Sebastien Binet 700cec440e gpu,op/clip: implement stroked paths with round joins
Signed-off-by: Sebastien Binet <s@sbinet.org>
2020-11-11 14:03:30 +01:00
Sebastien Binet 33c5fb63db gpu,op/clip: implement stroked paths
Flat and Square caps are implemented.
Bevel joins are implemented.

Round caps, Round joins and Miter joins are left for another PR.

Signed-off-by: Sebastien Binet <s@sbinet.org>
2020-11-10 15:58:10 +01:00
Elias Naur 94d242d18c op/paint: remove support for PaintOp.Rect
PaintOp.Rect is the wrong abstraction; it implies a clip operation
better handled by package clip, and not all paints need it (colors).
Furthermore, it's awkward to specify a PaintOp that fills up the
current clip area, regardless of its size.

Redefine PathOp to mean "fill current clip area".

API change. Replace uses of PaintOp.Rect with a TransformOp applied
before the PaintOp.

Leave a TODO for the PathOp infinity area.

Fixes gio#167

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-11-05 16:32:19 +01:00
Elias Naur 852958f4b5 gpu,widget,op/paint,gpu: remove support for ImageOp.Rect
This is effectively a revert of commit gioui.org/commit/69dfd2e3a5541.

ImageOp.Rect is the wrong abstraction; it implies a clipping operation that is
better handled by package clip.

API change. Uses of ImageOp.Rect should apply a clip.Rect before the PaintOp,
or use image.RGBA.SubImage (or similar).

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-11-05 13:36:36 +01:00
Elias Naur c62a002d21 gpu: remove unused field
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-11-05 10:15:46 +01:00
Egon Elbre f00f3a3359 gpu: add linear gradient
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2020-11-03 15:39:06 +01:00
Elias Naur 38cdd28681 gpu: fix depth buffer corruption on the Fairphone 2
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-11-02 19:44:56 +01:00
Elias Naur 7a4b48f67b gpu: delete redundant drawOps.reset
Noticed by Steve Lam

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-10-18 18:22:16 +02:00
Elias Naur 47efa26cfc gpu: limit atlas textures to 8k x 8k
Fixes gio#131
Fixes gio#133

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-07-16 14:52:51 +02:00