gpu, op, internal/ops: add affine transformations

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>
This commit is contained in:
Viktor
2020-06-20 23:29:51 +02:00
committed by Elias Naur
parent b247395c62
commit 24951a7ee7
9 changed files with 270 additions and 145 deletions
+18 -3
View File
@@ -5,6 +5,7 @@ package ops
import (
"encoding/binary"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/op"
)
@@ -26,9 +27,10 @@ type EncodedOp struct {
// Key is a unique key for a given op.
type Key struct {
ops *op.Ops
pc int
version int
ops *op.Ops
pc int
version int
sx, hx, sy, hy float32
}
// Shadow of op.MacroOp.
@@ -52,6 +54,10 @@ type opMacroDef struct {
endpc pc
}
func (r *Reader) NewKey(pc int) Key {
return Key{ops: r.ops, pc: pc, version: r.ops.Version()}
}
// Reset start reading from the op list.
func (r *Reader) Reset(ops *op.Ops) {
r.stack = r.stack[:0]
@@ -59,6 +65,15 @@ func (r *Reader) Reset(ops *op.Ops) {
r.ops = ops
}
func (k Key) SetTransform(t f32.Affine2D) Key {
sx, hx, sy, hy, _, _ := t.Elems()
k.sx = sx
k.hx = hx
k.sy = sy
k.hy = hy
return k
}
func (r *Reader) Decode() (EncodedOp, bool) {
if r.ops == nil {
return EncodedOp{}, false