From 2749eb91f32d15d2f588d2f6ab5f6941fa9e3af1 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 27 Aug 2021 10:40:35 +0200 Subject: [PATCH] gpu: [compute] clip image materials to their rendered size Before this change, transformed images would take up as much atlas texture space to fit them. However, we can easily run out of space for large images or images with large scaling applied. This change limits transformed images to their rendered bounds which is the window size in the worst case. Updates gio#219 (fixes the chat kitchen example) Signed-off-by: Elias Naur --- gpu/compute.go | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/gpu/compute.go b/gpu/compute.go index 70544708..ee9bdd87 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -285,6 +285,7 @@ type materialVertex struct { type textureKey struct { handle interface{} transform f32.Affine2D + bounds image.Rectangle } // textureOp represents an paintOp that requires texture space. @@ -936,7 +937,11 @@ func (g *compute) renderMaterials() error { break } imgAtlas = op.imgAlloc.atlas - quad, bounds := g.materialQuad(imgAtlas.size, op.key.transform, op.img, op.imgAlloc.rect.Min) + quad := g.materialQuad(imgAtlas.size, op.key.transform, op.img, op.imgAlloc.rect.Min) + boundsf := quadBounds(quad) + bounds := boundRectF(boundsf) + bounds = bounds.Intersect(op.key.bounds) + size := bounds.Size() alloc, fits := g.atlasAlloc(allocQuery{ atlas: atlas, @@ -1102,7 +1107,7 @@ func pow2Ceil(v int) int { // materialQuad constructs a quad that represents the transformed image. It returns the quad // and its bounds. -func (g *compute) materialQuad(imgAtlasSize image.Point, M f32.Affine2D, img imageOpData, uvPos image.Point) ([4]materialVertex, image.Rectangle) { +func (g *compute) materialQuad(imgAtlasSize image.Point, M f32.Affine2D, img imageOpData, uvPos image.Point) [4]materialVertex { imgSize := layout.FPt(img.src.Bounds().Size()) sx, hx, ox, hy, sy, oy := M.Elems() transOff := f32.Pt(ox, oy) @@ -1121,12 +1126,6 @@ func (g *compute) materialQuad(imgAtlasSize image.Point, M f32.Affine2D, img ima q2 = q2.Add(transOff) q3 = q3.Add(transOff) - boundsf := f32.Rectangle{ - Min: min(min(q0, q1), min(q2, q3)), - Max: max(max(q0, q1), max(q2, q3)), - } - - bounds := boundRectF(boundsf) uvPosf := layout.FPt(uvPos) atlasScale := f32.Pt(1/float32(imgAtlasSize.X), 1/float32(imgAtlasSize.Y)) uvBounds := f32.Rectangle{ @@ -1143,7 +1142,18 @@ func (g *compute) materialQuad(imgAtlasSize image.Point, M f32.Affine2D, img ima {posX: q2.X, posY: q2.Y, u: uvBounds.Max.X, v: uvBounds.Max.Y}, {posX: q3.X, posY: q3.Y, u: uvBounds.Max.X, v: uvBounds.Min.Y}, } - return quad, bounds + return quad +} + +func quadBounds(q [4]materialVertex) f32.Rectangle { + q0 := f32.Pt(q[0].posX, q[0].posY) + q1 := f32.Pt(q[1].posX, q[1].posY) + q2 := f32.Pt(q[2].posX, q[2].posY) + q3 := f32.Pt(q[3].posX, q[3].posY) + return f32.Rectangle{ + Min: min(min(q0, q1), min(q2, q3)), + Max: max(max(q0, q1), max(q2, q3)), + } } func max(p1, p2 f32.Point) f32.Point { @@ -1855,10 +1865,12 @@ func (c *collector) collect(root *op.Ops, viewport image.Point, texOps *[]textur // except for their integer offsets can share a transformed image. t := op.state.t.Offset(layout.FPt(op.offset)) t, off := separateTransform(t) + bounds := boundRectF(op.intersect).Sub(off) *texOps = append(*texOps, textureOp{ img: op.state.image, off: off, key: textureKey{ + bounds: bounds, transform: t, handle: op.state.image.handle, },