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 <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-08-27 10:40:35 +02:00
parent 9e9cb17a5d
commit 2749eb91f3
+21 -9
View File
@@ -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,
},