mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
gpu: replace f32.Point/Rectangle with image.Point/Rectangle
Signed-off-by: Walter Werner SCHNEIDER <contact@schnwalter.eu> Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
committed by
Elias Naur
parent
bbb6d05f09
commit
36a2fa37c7
+2
-3
@@ -4,8 +4,7 @@ package gpu
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"gioui.org/internal/f32"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type textureCacheKey struct {
|
type textureCacheKey struct {
|
||||||
@@ -36,7 +35,7 @@ type opCache struct {
|
|||||||
type opCacheValue struct {
|
type opCacheValue struct {
|
||||||
data pathData
|
data pathData
|
||||||
|
|
||||||
bounds f32.Rectangle
|
bounds image.Rectangle
|
||||||
// the fields below are handled by opCache
|
// the fields below are handled by opCache
|
||||||
key opKey
|
key opKey
|
||||||
keep bool
|
keep bool
|
||||||
|
|||||||
+50
-50
@@ -118,17 +118,17 @@ type drawState struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type pathOp struct {
|
type pathOp struct {
|
||||||
off f32.Point
|
off image.Point
|
||||||
// rect tracks whether the clip stack can be represented by a
|
// rect tracks whether the clip stack can be represented by a
|
||||||
// pixel-aligned rectangle.
|
// pixel-aligned rectangle.
|
||||||
rect bool
|
rect bool
|
||||||
// clip is the union of all
|
// clip is the union of all
|
||||||
// later clip rectangles.
|
// later clip rectangles.
|
||||||
clip image.Rectangle
|
clip image.Rectangle
|
||||||
bounds f32.Rectangle
|
bounds image.Rectangle
|
||||||
// intersect is the intersection of bounds and all
|
// intersect is the intersection of bounds and all
|
||||||
// previous clip bounds.
|
// previous clip bounds.
|
||||||
intersect f32.Rectangle
|
intersect image.Rectangle
|
||||||
pathKey opKey
|
pathKey opKey
|
||||||
path bool
|
path bool
|
||||||
pathVerts []byte
|
pathVerts []byte
|
||||||
@@ -902,16 +902,14 @@ func (d *drawOps) reset(viewport image.Point) {
|
|||||||
d.opacityStack = d.opacityStack[:0]
|
d.opacityStack = d.opacityStack[:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawOps) collect(root *op.Ops, viewport image.Point) {
|
func (d *drawOps) collect(root *op.Ops, viewportSize image.Point) {
|
||||||
viewf := f32.Rectangle{
|
viewport := image.Rectangle{Max: viewportSize}
|
||||||
Max: f32.Point{X: float32(viewport.X), Y: float32(viewport.Y)},
|
|
||||||
}
|
|
||||||
var ops *ops.Ops
|
var ops *ops.Ops
|
||||||
if root != nil {
|
if root != nil {
|
||||||
ops = &root.Internal
|
ops = &root.Internal
|
||||||
}
|
}
|
||||||
d.reader.Reset(ops)
|
d.reader.Reset(ops)
|
||||||
d.collectOps(&d.reader, viewf)
|
d.collectOps(&d.reader, viewport)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawOps) buildPaths(ctx driver.Device) {
|
func (d *drawOps) buildPaths(ctx driver.Device) {
|
||||||
@@ -932,7 +930,7 @@ func (d *drawOps) newPathOp() *pathOp {
|
|||||||
return &d.pathOpCache[len(d.pathOpCache)-1]
|
return &d.pathOpCache[len(d.pathOpCache)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawOps) addClipPath(state *drawState, aux []byte, auxKey opKey, bounds f32.Rectangle, off f32.Point) {
|
func (d *drawOps) addClipPath(state *drawState, aux []byte, auxKey opKey, bounds image.Rectangle, off image.Point) {
|
||||||
npath := d.newPathOp()
|
npath := d.newPathOp()
|
||||||
*npath = pathOp{
|
*npath = pathOp{
|
||||||
parent: state.cpath,
|
parent: state.cpath,
|
||||||
@@ -973,7 +971,7 @@ func (k opKey) SetTransform(t f32.Affine2D) opKey {
|
|||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawOps) collectOps(r *ops.Reader, viewport f32.Rectangle) {
|
func (d *drawOps) collectOps(r *ops.Reader, viewport image.Rectangle) {
|
||||||
var quads quadsOp
|
var quads quadsOp
|
||||||
state := drawState{
|
state := drawState{
|
||||||
t: f32.AffineId(),
|
t: f32.AffineId(),
|
||||||
@@ -1035,7 +1033,7 @@ loop:
|
|||||||
var op ops.ClipOp
|
var op ops.ClipOp
|
||||||
op.Decode(encOp.Data)
|
op.Decode(encOp.Data)
|
||||||
quads.key.outline = op.Outline
|
quads.key.outline = op.Outline
|
||||||
bounds := f32.FRect(op.Bounds)
|
bounds := op.Bounds
|
||||||
trans, off := transformOffset(state.t)
|
trans, off := transformOffset(state.t)
|
||||||
if len(quads.aux) > 0 {
|
if len(quads.aux) > 0 {
|
||||||
// There is a clipping path, build the gpu data and update the
|
// There is a clipping path, build the gpu data and update the
|
||||||
@@ -1047,11 +1045,11 @@ loop:
|
|||||||
// Why is this not used for the offset shapes?
|
// Why is this not used for the offset shapes?
|
||||||
bounds = v.bounds
|
bounds = v.bounds
|
||||||
} else {
|
} else {
|
||||||
var pathData []byte
|
newPathData, newBounds := d.buildVerts(
|
||||||
pathData, bounds = d.buildVerts(
|
|
||||||
quads.aux, trans, quads.key.outline, quads.key.strokeWidth,
|
quads.aux, trans, quads.key.outline, quads.key.strokeWidth,
|
||||||
)
|
)
|
||||||
quads.aux = pathData
|
quads.aux = newPathData
|
||||||
|
bounds = newBounds.Round()
|
||||||
// add it to the cache, without GPU data, so the transform can be
|
// add it to the cache, without GPU data, so the transform can be
|
||||||
// reused.
|
// reused.
|
||||||
d.pathCache.put(quads.key, opCacheValue{bounds: bounds})
|
d.pathCache.put(quads.key, opCacheValue{bounds: bounds})
|
||||||
@@ -1086,18 +1084,18 @@ loop:
|
|||||||
t, off := transformOffset(state.t)
|
t, off := transformOffset(state.t)
|
||||||
// Fill the clip area, unless the material is a (bounded) image.
|
// Fill the clip area, unless the material is a (bounded) image.
|
||||||
// TODO: Find a tighter bound.
|
// TODO: Find a tighter bound.
|
||||||
inf := float32(1e6)
|
inf := int(1e6)
|
||||||
dst := f32.Rect(-inf, -inf, inf, inf)
|
dst := image.Rect(-inf, -inf, inf, inf)
|
||||||
if state.matType == materialTexture {
|
if state.matType == materialTexture {
|
||||||
sz := state.image.src.Rect.Size()
|
sz := state.image.src.Rect.Size()
|
||||||
dst = f32.Rectangle{Max: layout.FPt(sz)}
|
dst = image.Rectangle{Max: sz}
|
||||||
}
|
}
|
||||||
clipData, bnd, partialTrans := d.boundsForTransformedRect(dst, t)
|
clipData, bnd, partialTrans := d.boundsForTransformedRect(dst, t)
|
||||||
cl := viewport.Intersect(bnd.Add(off))
|
bounds := viewport.Intersect(bnd.Add(off))
|
||||||
if state.cpath != nil {
|
if state.cpath != nil {
|
||||||
cl = state.cpath.intersect.Intersect(cl)
|
bounds = state.cpath.intersect.Intersect(bounds)
|
||||||
}
|
}
|
||||||
if cl.Empty() {
|
if bounds.Empty() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1109,7 +1107,6 @@ loop:
|
|||||||
d.addClipPath(&state, clipData, k, bnd, off)
|
d.addClipPath(&state, clipData, k, bnd, off)
|
||||||
}
|
}
|
||||||
|
|
||||||
bounds := cl.Round()
|
|
||||||
mat := state.materialFor(bnd, off, partialTrans, bounds)
|
mat := state.materialFor(bnd, off, partialTrans, bounds)
|
||||||
|
|
||||||
rect := state.cpath == nil || state.cpath.rect
|
rect := state.cpath == nil || state.cpath.rect
|
||||||
@@ -1163,7 +1160,7 @@ func expandPathOp(p *pathOp, clip image.Rectangle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawState) materialFor(rect f32.Rectangle, off f32.Point, partTrans f32.Affine2D, clip image.Rectangle) material {
|
func (d *drawState) materialFor(rect image.Rectangle, off image.Point, partTrans f32.Affine2D, clip image.Rectangle) material {
|
||||||
m := material{
|
m := material{
|
||||||
opacity: 1.,
|
opacity: 1.,
|
||||||
uvTrans: f32.AffineId(),
|
uvTrans: f32.AffineId(),
|
||||||
@@ -1183,7 +1180,7 @@ func (d *drawState) materialFor(rect f32.Rectangle, off f32.Point, partTrans f32
|
|||||||
m.uvTrans = partTrans.Mul(gradientSpaceTransform(clip, off, d.stop1, d.stop2))
|
m.uvTrans = partTrans.Mul(gradientSpaceTransform(clip, off, d.stop1, d.stop2))
|
||||||
case materialTexture:
|
case materialTexture:
|
||||||
m.material = materialTexture
|
m.material = materialTexture
|
||||||
dr := rect.Add(off).Round()
|
dr := rect.Add(off)
|
||||||
sz := d.image.src.Bounds().Size()
|
sz := d.image.src.Bounds().Size()
|
||||||
sr := f32.Rectangle{
|
sr := f32.Rectangle{
|
||||||
Max: f32.Point{
|
Max: f32.Point{
|
||||||
@@ -1368,7 +1365,7 @@ func texSpaceTransform(r f32.Rectangle, bounds image.Point) (f32.Point, f32.Poin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// gradientSpaceTransform transforms stop1 and stop2 to [(0,0), (1,1)].
|
// gradientSpaceTransform transforms stop1 and stop2 to [(0,0), (1,1)].
|
||||||
func gradientSpaceTransform(clip image.Rectangle, off f32.Point, stop1, stop2 f32.Point) f32.Affine2D {
|
func gradientSpaceTransform(clip image.Rectangle, off image.Point, stop1, stop2 f32.Point) f32.Affine2D {
|
||||||
d := stop2.Sub(stop1)
|
d := stop2.Sub(stop1)
|
||||||
l := float32(math.Sqrt(float64(d.X*d.X + d.Y*d.Y)))
|
l := float32(math.Sqrt(float64(d.X*d.X + d.Y*d.Y)))
|
||||||
a := float32(math.Atan2(float64(-d.Y), float64(d.X)))
|
a := float32(math.Atan2(float64(-d.Y), float64(d.X)))
|
||||||
@@ -1376,11 +1373,11 @@ func gradientSpaceTransform(clip image.Rectangle, off f32.Point, stop1, stop2 f3
|
|||||||
// TODO: optimize
|
// TODO: optimize
|
||||||
zp := f32.Point{}
|
zp := f32.Point{}
|
||||||
return f32.AffineId().
|
return f32.AffineId().
|
||||||
Scale(zp, layout.FPt(clip.Size())). // scale to pixel space
|
Scale(zp, layout.FPt(clip.Size())). // scale to pixel space
|
||||||
Offset(zp.Sub(off).Add(layout.FPt(clip.Min))). // offset to clip space
|
Offset(zp.Sub(f32.FPt(off)).Add(layout.FPt(clip.Min))). // offset to clip space
|
||||||
Offset(zp.Sub(stop1)). // offset to first stop point
|
Offset(zp.Sub(stop1)). // offset to first stop point
|
||||||
Rotate(zp, a). // rotate to align gradient
|
Rotate(zp, a). // rotate to align gradient
|
||||||
Scale(zp, f32.Pt(1/l, 1/l)) // scale gradient to right size
|
Scale(zp, f32.Pt(1/l, 1/l)) // scale gradient to right size
|
||||||
}
|
}
|
||||||
|
|
||||||
// clipSpaceTransform returns the scale and offset that transforms the given
|
// clipSpaceTransform returns the scale and offset that transforms the given
|
||||||
@@ -1524,7 +1521,7 @@ func decodeToOutlineQuads(qs *quadSplitter, tr f32.Affine2D, pathData []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create GPU vertices for transformed r, find the bounds and establish texture transform.
|
// create GPU vertices for transformed r, find the bounds and establish texture transform.
|
||||||
func (d *drawOps) boundsForTransformedRect(r f32.Rectangle, tr f32.Affine2D) (aux []byte, bnd f32.Rectangle, ptr f32.Affine2D) {
|
func (d *drawOps) boundsForTransformedRect(r image.Rectangle, tr f32.Affine2D) (aux []byte, bnd image.Rectangle, ptr f32.Affine2D) {
|
||||||
ptr = f32.AffineId()
|
ptr = f32.AffineId()
|
||||||
if tr == f32.AffineId() {
|
if tr == f32.AffineId() {
|
||||||
// fast-path to allow blitting of pure rectangles.
|
// fast-path to allow blitting of pure rectangles.
|
||||||
@@ -1534,25 +1531,28 @@ func (d *drawOps) boundsForTransformedRect(r f32.Rectangle, tr f32.Affine2D) (au
|
|||||||
|
|
||||||
// transform all corners, find new bounds
|
// transform all corners, find new bounds
|
||||||
corners := [4]f32.Point{
|
corners := [4]f32.Point{
|
||||||
tr.Transform(r.Min), tr.Transform(f32.Pt(r.Max.X, r.Min.Y)),
|
tr.Transform(f32.FPt(r.Min)), tr.Transform(f32.Pt(float32(r.Max.X), float32(r.Min.Y))),
|
||||||
tr.Transform(r.Max), tr.Transform(f32.Pt(r.Min.X, r.Max.Y)),
|
tr.Transform(f32.FPt(r.Max)), tr.Transform(f32.Pt(float32(r.Min.X), float32(r.Max.Y))),
|
||||||
|
}
|
||||||
|
fBounds := f32.Rectangle{
|
||||||
|
Min: f32.Pt(math.MaxFloat32, math.MaxFloat32),
|
||||||
|
Max: f32.Pt(-math.MaxFloat32, -math.MaxFloat32),
|
||||||
}
|
}
|
||||||
bnd.Min = f32.Pt(math.MaxFloat32, math.MaxFloat32)
|
|
||||||
bnd.Max = f32.Pt(-math.MaxFloat32, -math.MaxFloat32)
|
|
||||||
for _, c := range corners {
|
for _, c := range corners {
|
||||||
if c.X < bnd.Min.X {
|
if c.X < fBounds.Min.X {
|
||||||
bnd.Min.X = c.X
|
fBounds.Min.X = c.X
|
||||||
}
|
}
|
||||||
if c.Y < bnd.Min.Y {
|
if c.Y < fBounds.Min.Y {
|
||||||
bnd.Min.Y = c.Y
|
fBounds.Min.Y = c.Y
|
||||||
}
|
}
|
||||||
if c.X > bnd.Max.X {
|
if c.X > fBounds.Max.X {
|
||||||
bnd.Max.X = c.X
|
fBounds.Max.X = c.X
|
||||||
}
|
}
|
||||||
if c.Y > bnd.Max.Y {
|
if c.Y > fBounds.Max.Y {
|
||||||
bnd.Max.Y = c.Y
|
fBounds.Max.Y = c.Y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bnd = fBounds.Round()
|
||||||
|
|
||||||
// build the GPU vertices
|
// build the GPU vertices
|
||||||
l := len(d.vertCache)
|
l := len(d.vertCache)
|
||||||
@@ -1566,12 +1566,12 @@ func (d *drawOps) boundsForTransformedRect(r f32.Rectangle, tr f32.Affine2D) (au
|
|||||||
|
|
||||||
// establish the transform mapping from bounds rectangle to transformed corners
|
// establish the transform mapping from bounds rectangle to transformed corners
|
||||||
var P1, P2, P3 f32.Point
|
var P1, P2, P3 f32.Point
|
||||||
P1.X = (corners[1].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
|
P1.X = (corners[1].X - fBounds.Min.X) / (fBounds.Max.X - fBounds.Min.X)
|
||||||
P1.Y = (corners[1].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.Min.Y)
|
P1.Y = (corners[1].Y - fBounds.Min.Y) / (fBounds.Max.Y - fBounds.Min.Y)
|
||||||
P2.X = (corners[2].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
|
P2.X = (corners[2].X - fBounds.Min.X) / (fBounds.Max.X - fBounds.Min.X)
|
||||||
P2.Y = (corners[2].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.Min.Y)
|
P2.Y = (corners[2].Y - fBounds.Min.Y) / (fBounds.Max.Y - fBounds.Min.Y)
|
||||||
P3.X = (corners[3].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
|
P3.X = (corners[3].X - fBounds.Min.X) / (fBounds.Max.X - fBounds.Min.X)
|
||||||
P3.Y = (corners[3].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.Min.Y)
|
P3.Y = (corners[3].Y - fBounds.Min.Y) / (fBounds.Max.Y - fBounds.Min.Y)
|
||||||
sx, sy := P2.X-P3.X, P2.Y-P3.Y
|
sx, sy := P2.X-P3.X, P2.Y-P3.Y
|
||||||
ptr = f32.NewAffine2D(sx, P2.X-P1.X, P1.X-sx, sy, P2.Y-P1.Y, P1.Y-sy).Invert()
|
ptr = f32.NewAffine2D(sx, P2.X-P1.X, P1.X-sx, sy, P2.Y-P1.Y, P1.Y-sy).Invert()
|
||||||
|
|
||||||
@@ -1581,12 +1581,12 @@ func (d *drawOps) boundsForTransformedRect(r f32.Rectangle, tr f32.Affine2D) (au
|
|||||||
// transformOffset a transform into two parts, one which is pure integer offset
|
// transformOffset a transform into two parts, one which is pure integer offset
|
||||||
// and the other representing the scaling, shearing and rotation and fractional
|
// and the other representing the scaling, shearing and rotation and fractional
|
||||||
// offset.
|
// offset.
|
||||||
func transformOffset(t f32.Affine2D) (f32.Affine2D, f32.Point) {
|
func transformOffset(t f32.Affine2D) (f32.Affine2D, image.Point) {
|
||||||
sx, hx, ox, hy, sy, oy := t.Elems()
|
sx, hx, ox, hy, sy, oy := t.Elems()
|
||||||
iox, fox := math.Modf(float64(ox))
|
iox, fox := math.Modf(float64(ox))
|
||||||
ioy, foy := math.Modf(float64(oy))
|
ioy, foy := math.Modf(float64(oy))
|
||||||
ft := f32.NewAffine2D(sx, hx, float32(fox), hy, sy, float32(foy))
|
ft := f32.NewAffine2D(sx, hx, float32(fox), hy, sy, float32(foy))
|
||||||
ip := f32.Pt(float32(iox), float32(ioy))
|
ip := image.Pt(int(iox), int(ioy))
|
||||||
return ft, ip
|
return ft, ip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -334,7 +334,7 @@ func (p *pather) begin(sizes []image.Point) {
|
|||||||
p.stenciler.begin(sizes)
|
p.stenciler.begin(sizes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pather) stencilPath(bounds image.Rectangle, offset f32.Point, uv image.Point, data pathData) {
|
func (p *pather) stencilPath(bounds image.Rectangle, offset image.Point, uv image.Point, data pathData) {
|
||||||
p.stenciler.stencilPath(bounds, offset, uv, data)
|
p.stenciler.stencilPath(bounds, offset, uv, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,14 +353,14 @@ func (s *stenciler) begin(sizes []image.Point) {
|
|||||||
s.fbos.resize(s.ctx, driver.TextureFormatFloat, sizes)
|
s.fbos.resize(s.ctx, driver.TextureFormatFloat, sizes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.Point, uv image.Point, data pathData) {
|
func (s *stenciler) stencilPath(bounds image.Rectangle, offset image.Point, uv image.Point, data pathData) {
|
||||||
s.ctx.Viewport(uv.X, uv.Y, bounds.Dx(), bounds.Dy())
|
s.ctx.Viewport(uv.X, uv.Y, bounds.Dx(), bounds.Dy())
|
||||||
// Transform UI coordinates to OpenGL coordinates.
|
// Transform UI coordinates to OpenGL coordinates.
|
||||||
texSize := f32.Point{X: float32(bounds.Dx()), Y: float32(bounds.Dy())}
|
texSize := f32.Point{X: float32(bounds.Dx()), Y: float32(bounds.Dy())}
|
||||||
scale := f32.Point{X: 2 / texSize.X, Y: 2 / texSize.Y}
|
scale := f32.Point{X: 2 / texSize.X, Y: 2 / texSize.Y}
|
||||||
orig := f32.Point{X: -1 - float32(bounds.Min.X)*2/texSize.X, Y: -1 - float32(bounds.Min.Y)*2/texSize.Y}
|
orig := f32.Point{X: -1 - float32(bounds.Min.X)*2/texSize.X, Y: -1 - float32(bounds.Min.Y)*2/texSize.Y}
|
||||||
s.pipeline.uniforms.transform = [4]float32{scale.X, scale.Y, orig.X, orig.Y}
|
s.pipeline.uniforms.transform = [4]float32{scale.X, scale.Y, orig.X, orig.Y}
|
||||||
s.pipeline.uniforms.pathOffset = [2]float32{offset.X, offset.Y}
|
s.pipeline.uniforms.pathOffset = [2]float32{float32(offset.X), float32(offset.Y)}
|
||||||
s.pipeline.pipeline.UploadUniforms(s.ctx)
|
s.pipeline.pipeline.UploadUniforms(s.ctx)
|
||||||
// Draw in batches that fit in uint16 indices.
|
// Draw in batches that fit in uint16 indices.
|
||||||
start := 0
|
start := 0
|
||||||
|
|||||||
Reference in New Issue
Block a user