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 { type textureKey struct {
handle interface{} handle interface{}
transform f32.Affine2D transform f32.Affine2D
bounds image.Rectangle
} }
// textureOp represents an paintOp that requires texture space. // textureOp represents an paintOp that requires texture space.
@@ -936,7 +937,11 @@ func (g *compute) renderMaterials() error {
break break
} }
imgAtlas = op.imgAlloc.atlas 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() size := bounds.Size()
alloc, fits := g.atlasAlloc(allocQuery{ alloc, fits := g.atlasAlloc(allocQuery{
atlas: atlas, atlas: atlas,
@@ -1102,7 +1107,7 @@ func pow2Ceil(v int) int {
// materialQuad constructs a quad that represents the transformed image. It returns the quad // materialQuad constructs a quad that represents the transformed image. It returns the quad
// and its bounds. // 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()) imgSize := layout.FPt(img.src.Bounds().Size())
sx, hx, ox, hy, sy, oy := M.Elems() sx, hx, ox, hy, sy, oy := M.Elems()
transOff := f32.Pt(ox, oy) 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) q2 = q2.Add(transOff)
q3 = q3.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) uvPosf := layout.FPt(uvPos)
atlasScale := f32.Pt(1/float32(imgAtlasSize.X), 1/float32(imgAtlasSize.Y)) atlasScale := f32.Pt(1/float32(imgAtlasSize.X), 1/float32(imgAtlasSize.Y))
uvBounds := f32.Rectangle{ 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: 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}, {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 { 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. // except for their integer offsets can share a transformed image.
t := op.state.t.Offset(layout.FPt(op.offset)) t := op.state.t.Offset(layout.FPt(op.offset))
t, off := separateTransform(t) t, off := separateTransform(t)
bounds := boundRectF(op.intersect).Sub(off)
*texOps = append(*texOps, textureOp{ *texOps = append(*texOps, textureOp{
img: op.state.image, img: op.state.image,
off: off, off: off,
key: textureKey{ key: textureKey{
bounds: bounds,
transform: t, transform: t,
handle: op.state.image.handle, handle: op.state.image.handle,
}, },