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>
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>
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>
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>
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>
While here, merge BeginFrame and EndFrame; the split was done for
performance reasons, yet never measured.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
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>
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>
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>
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>
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>
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>
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>
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>
Fixes a bug due to that f32.Rect.Intersect will not return the
empty rectangle for non intersecting rectangles - but instead
a swapped rectangle. By removing the .Canon() call in gpu.go we
ensure that non overlapping clipping rects and paint rects will
lead to no painting.
The Canon() call is not needed since boundsForTransformedRect()
was previously updated to always return a canonical rectangle.
Test case added.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
This commit fixes a bug where a shape first drawn off-screen
and later moved into screen would not display properly. Since we
cache CPU operations (vertex transform / construction) we need to
upload the constructed data to the GPU after it was build, or a later
frame will use non-initialized memory for it's draw call.
Note that this fix removes the optimization of not processing clip
paths outside the screen - but this is assumed to be uncommon except
when it is first drawn off screen to later be moved in (e.g. in a scrolling list)
in which case we do want to upload the data and prepare for that later
call.
This commit also does a few minor clean ups and adds a test case.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
To avoid duplicate work when using macros and non-offset transforms,
cache also the new bounding boxes set up for them. The ops.Reader
already generates Keys for all operations, so use them in the cache.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
Previously the cache was only filled during gpu-buffer creation,
resulting in extra work on the CPU to transform vertices if the same
shape was used multiple times in the same frame. Cases such as font
rendering was cached already before this change as it is drawn in it's
own op.Ops that is never reset - and thus re-used from one frame
to the next.
Since we are now calling put() twice per frame an update should no
longer panic.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
Reintroduce support for offset in stencil vertex so we can reuse
cached values if the only difference in transform is offset. Split
current transform into a pure-offset part and the rest and use
only the complex part as cache key.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
Cache also CPU operations by moving pathCache into
drawOps and use it in collectOps to avoid splitting and
transformation of quads if in cache. In order to support
this use a concrete type in opCache instead of interface.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
Add support for affine transformations. The key changes are outlined
below.
- Painting/clipping with rectangles is handled by, for complex
transforms, creating clipping paths representing the transformed
rectangle and using a larger bounding box. Cover/Blit shaders updated
correspondingly to correctly map texture cordinates from the new
bounding boxes.
- Since path splitting must happen on CPU the transforms must happen CPU
side as well - offsets removed from shaders.
- Complex transforms will lead to different path splitting which means
that GPU arrays can no longer be cached if the transform has changed.
Thus the current transform is added as a key to the cache.
- Add a public API to op for setting Affine transformations.
There are a number of optimizations that could be explored further but
which are left out now:
- Caching also of CPU operations (e.g path splitting & transforms) and
not only caching the GPU arrays.
- Allow for re-use of cached GPU vertices if the transformation change
is a pure offset / scaling since the splitting is then the same.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
Encode TransformOp as an Affince2D matrix instead and use that in gpu and io transform handling.
There are no changes to user facing API and so far only the offset part of the matrix is used.
This patch is a step towards full affine transformations.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
This is a first step towards supporting affine drawing transforms.
The rendering algorithm relies on quadratic curves that do not cross
x = 0 more than once, thus curves must be split after any rotation/shear
transforms. Move this logic and the generation of vertices to package gpu.
Also close all curves and draw zero-width edges as preparation for
transform since the will no longer implicitly be vertical with no
effect.
This commit will severely affect performance since vertexes are now
transformed also for cached items, using cpu resources.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
Use greater-than-or-equal test and saturate the z depth buffer
when more than 65k objects are drawn.
Fixes gio#127
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The macOS backend doesn't re-create contexts, holding on to the first
created instead. Make sure the GPU leaves the default framebuffer bound,
in case the context is re-used.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Specifying the clear color and depth at the time of clearing is
less error prone and a better for modern GPU APIs. As a bonus, we
can get rid of the BufferAttachment type.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Uniform buffers are byte slice backed by Go structs. However, if a uniform
buffer value is embedded in a larger structure with pointers, the Cgo
pointer checker will complain. Avoid the error by moving the uniform
values into separate structures.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
DefaultFramebuffer was set up at Backend creation time, which is
difficult to predict. Instead, let GPU query and cache the current
FBO when created.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
"handling" means panicing, but at least the panicing is moved up
a layer, leaving future changes to do it properly in GPU.
Signed-off-by: Elias Naur <mail@eliasnaur.com>