forked from joejulian/gio
Revert "gpu: replace f32.Point/Rectangle with image.Point/Rectangle"
This reverts commit 36a2fa37c7.
Reason is that text rendering broke on some Android devices[0].
[0] https://lists.sr.ht/~eliasnaur/gio/%3CPH7PR02MB1003858FA1B27C8A53BE96815DDA1A@PH7PR02MB10038.namprd02.prod.outlook.com%3E
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+3
-2
@@ -4,7 +4,8 @@ package gpu
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
|
||||||
|
"gioui.org/internal/f32"
|
||||||
)
|
)
|
||||||
|
|
||||||
type textureCacheKey struct {
|
type textureCacheKey struct {
|
||||||
@@ -35,7 +36,7 @@ type opCache struct {
|
|||||||
type opCacheValue struct {
|
type opCacheValue struct {
|
||||||
data pathData
|
data pathData
|
||||||
|
|
||||||
bounds image.Rectangle
|
bounds f32.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 image.Point
|
off f32.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 image.Rectangle
|
bounds f32.Rectangle
|
||||||
// intersect is the intersection of bounds and all
|
// intersect is the intersection of bounds and all
|
||||||
// previous clip bounds.
|
// previous clip bounds.
|
||||||
intersect image.Rectangle
|
intersect f32.Rectangle
|
||||||
pathKey opKey
|
pathKey opKey
|
||||||
path bool
|
path bool
|
||||||
pathVerts []byte
|
pathVerts []byte
|
||||||
@@ -902,14 +902,16 @@ func (d *drawOps) reset(viewport image.Point) {
|
|||||||
d.opacityStack = d.opacityStack[:0]
|
d.opacityStack = d.opacityStack[:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawOps) collect(root *op.Ops, viewportSize image.Point) {
|
func (d *drawOps) collect(root *op.Ops, viewport image.Point) {
|
||||||
viewport := image.Rectangle{Max: viewportSize}
|
viewf := f32.Rectangle{
|
||||||
|
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, viewport)
|
d.collectOps(&d.reader, viewf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawOps) buildPaths(ctx driver.Device) {
|
func (d *drawOps) buildPaths(ctx driver.Device) {
|
||||||
@@ -930,7 +932,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 image.Rectangle, off image.Point) {
|
func (d *drawOps) addClipPath(state *drawState, aux []byte, auxKey opKey, bounds f32.Rectangle, off f32.Point) {
|
||||||
npath := d.newPathOp()
|
npath := d.newPathOp()
|
||||||
*npath = pathOp{
|
*npath = pathOp{
|
||||||
parent: state.cpath,
|
parent: state.cpath,
|
||||||
@@ -971,7 +973,7 @@ func (k opKey) SetTransform(t f32.Affine2D) opKey {
|
|||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawOps) collectOps(r *ops.Reader, viewport image.Rectangle) {
|
func (d *drawOps) collectOps(r *ops.Reader, viewport f32.Rectangle) {
|
||||||
var quads quadsOp
|
var quads quadsOp
|
||||||
state := drawState{
|
state := drawState{
|
||||||
t: f32.AffineId(),
|
t: f32.AffineId(),
|
||||||
@@ -1033,7 +1035,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 := op.Bounds
|
bounds := f32.FRect(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
|
||||||
@@ -1045,11 +1047,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 {
|
||||||
newPathData, newBounds := d.buildVerts(
|
var pathData []byte
|
||||||
|
pathData, bounds = d.buildVerts(
|
||||||
quads.aux, trans, quads.key.outline, quads.key.strokeWidth,
|
quads.aux, trans, quads.key.outline, quads.key.strokeWidth,
|
||||||
)
|
)
|
||||||
quads.aux = newPathData
|
quads.aux = pathData
|
||||||
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})
|
||||||
@@ -1084,18 +1086,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 := int(1e6)
|
inf := float32(1e6)
|
||||||
dst := image.Rect(-inf, -inf, inf, inf)
|
dst := f32.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 = image.Rectangle{Max: sz}
|
dst = f32.Rectangle{Max: layout.FPt(sz)}
|
||||||
}
|
}
|
||||||
clipData, bnd, partialTrans := d.boundsForTransformedRect(dst, t)
|
clipData, bnd, partialTrans := d.boundsForTransformedRect(dst, t)
|
||||||
bounds := viewport.Intersect(bnd.Add(off))
|
cl := viewport.Intersect(bnd.Add(off))
|
||||||
if state.cpath != nil {
|
if state.cpath != nil {
|
||||||
bounds = state.cpath.intersect.Intersect(bounds)
|
cl = state.cpath.intersect.Intersect(cl)
|
||||||
}
|
}
|
||||||
if bounds.Empty() {
|
if cl.Empty() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1107,6 +1109,7 @@ 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
|
||||||
@@ -1160,7 +1163,7 @@ func expandPathOp(p *pathOp, clip image.Rectangle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawState) materialFor(rect image.Rectangle, off image.Point, partTrans f32.Affine2D, clip image.Rectangle) material {
|
func (d *drawState) materialFor(rect f32.Rectangle, off f32.Point, partTrans f32.Affine2D, clip image.Rectangle) material {
|
||||||
m := material{
|
m := material{
|
||||||
opacity: 1.,
|
opacity: 1.,
|
||||||
uvTrans: f32.AffineId(),
|
uvTrans: f32.AffineId(),
|
||||||
@@ -1180,7 +1183,7 @@ func (d *drawState) materialFor(rect image.Rectangle, off image.Point, partTrans
|
|||||||
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)
|
dr := rect.Add(off).Round()
|
||||||
sz := d.image.src.Bounds().Size()
|
sz := d.image.src.Bounds().Size()
|
||||||
sr := f32.Rectangle{
|
sr := f32.Rectangle{
|
||||||
Max: f32.Point{
|
Max: f32.Point{
|
||||||
@@ -1365,7 +1368,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 image.Point, stop1, stop2 f32.Point) f32.Affine2D {
|
func gradientSpaceTransform(clip image.Rectangle, off f32.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)))
|
||||||
@@ -1373,11 +1376,11 @@ func gradientSpaceTransform(clip image.Rectangle, off image.Point, stop1, stop2
|
|||||||
// 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(f32.FPt(off)).Add(layout.FPt(clip.Min))). // offset to clip space
|
Offset(zp.Sub(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
|
||||||
@@ -1521,7 +1524,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 image.Rectangle, tr f32.Affine2D) (aux []byte, bnd image.Rectangle, ptr f32.Affine2D) {
|
func (d *drawOps) boundsForTransformedRect(r f32.Rectangle, tr f32.Affine2D) (aux []byte, bnd f32.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.
|
||||||
@@ -1531,28 +1534,25 @@ func (d *drawOps) boundsForTransformedRect(r image.Rectangle, tr f32.Affine2D) (
|
|||||||
|
|
||||||
// transform all corners, find new bounds
|
// transform all corners, find new bounds
|
||||||
corners := [4]f32.Point{
|
corners := [4]f32.Point{
|
||||||
tr.Transform(f32.FPt(r.Min)), tr.Transform(f32.Pt(float32(r.Max.X), float32(r.Min.Y))),
|
tr.Transform(r.Min), tr.Transform(f32.Pt(r.Max.X, r.Min.Y)),
|
||||||
tr.Transform(f32.FPt(r.Max)), tr.Transform(f32.Pt(float32(r.Min.X), float32(r.Max.Y))),
|
tr.Transform(r.Max), tr.Transform(f32.Pt(r.Min.X, 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 < fBounds.Min.X {
|
if c.X < bnd.Min.X {
|
||||||
fBounds.Min.X = c.X
|
bnd.Min.X = c.X
|
||||||
}
|
}
|
||||||
if c.Y < fBounds.Min.Y {
|
if c.Y < bnd.Min.Y {
|
||||||
fBounds.Min.Y = c.Y
|
bnd.Min.Y = c.Y
|
||||||
}
|
}
|
||||||
if c.X > fBounds.Max.X {
|
if c.X > bnd.Max.X {
|
||||||
fBounds.Max.X = c.X
|
bnd.Max.X = c.X
|
||||||
}
|
}
|
||||||
if c.Y > fBounds.Max.Y {
|
if c.Y > bnd.Max.Y {
|
||||||
fBounds.Max.Y = c.Y
|
bnd.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 image.Rectangle, tr f32.Affine2D) (
|
|||||||
|
|
||||||
// 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 - fBounds.Min.X) / (fBounds.Max.X - fBounds.Min.X)
|
P1.X = (corners[1].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
|
||||||
P1.Y = (corners[1].Y - fBounds.Min.Y) / (fBounds.Max.Y - fBounds.Min.Y)
|
P1.Y = (corners[1].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.Min.Y)
|
||||||
P2.X = (corners[2].X - fBounds.Min.X) / (fBounds.Max.X - fBounds.Min.X)
|
P2.X = (corners[2].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
|
||||||
P2.Y = (corners[2].Y - fBounds.Min.Y) / (fBounds.Max.Y - fBounds.Min.Y)
|
P2.Y = (corners[2].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.Min.Y)
|
||||||
P3.X = (corners[3].X - fBounds.Min.X) / (fBounds.Max.X - fBounds.Min.X)
|
P3.X = (corners[3].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
|
||||||
P3.Y = (corners[3].Y - fBounds.Min.Y) / (fBounds.Max.Y - fBounds.Min.Y)
|
P3.Y = (corners[3].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.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 image.Rectangle, tr f32.Affine2D) (
|
|||||||
// 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, image.Point) {
|
func transformOffset(t f32.Affine2D) (f32.Affine2D, f32.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 := image.Pt(int(iox), int(ioy))
|
ip := f32.Pt(float32(iox), float32(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 image.Point, uv image.Point, data pathData) {
|
func (p *pather) stencilPath(bounds image.Rectangle, offset f32.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 image.Point, uv image.Point, data pathData) {
|
func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.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{float32(offset.X), float32(offset.Y)}
|
s.pipeline.uniforms.pathOffset = [2]float32{offset.X, 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