diff --git a/pixelgl/canvas.go b/pixelgl/canvas.go
index 1bf67af..7c2d781 100644
--- a/pixelgl/canvas.go
+++ b/pixelgl/canvas.go
@@ -27,8 +27,9 @@ type Canvas struct {
 	pixels []uint8
 	dirty  bool
 
-	bounds pixel.Rect
-	orig   *Canvas
+	borders pixel.Rect
+	bounds  pixel.Rect
+	orig    *Canvas
 }
 
 // NewCanvas creates a new empty, fully transparent Canvas with given bounds. If the smooth flag
@@ -161,7 +162,10 @@ func (c *Canvas) SetColorMask(col color.Color) {
 // If this Canvas was created using Slice-ing, then the relation between this Canvas and it's
 // Original is unspecified (but Original will always return valid stuff).
 func (c *Canvas) SetBounds(bounds pixel.Rect) {
-	if c.Bounds() == bounds {
+	c.bounds = bounds
+
+	// if this bounds fit into the original bounds, no need to reallocate
+	if c.orig.borders.Contains(bounds.Pos) && c.orig.borders.Contains(bounds.Pos+bounds.Size) {
 		return
 	}
 
@@ -184,8 +188,8 @@ func (c *Canvas) SetBounds(bounds pixel.Rect) {
 		}
 	})
 
-	c.bounds = bounds
 	c.orig = c // detach from the Original
+	c.borders = bounds
 	c.dirty = true
 }
 
@@ -209,7 +213,7 @@ func (c *Canvas) Smooth() bool {
 // must be manually called inside mainthread
 func (c *Canvas) setGlhfBounds() {
 	bounds := c.bounds
-	bounds.Pos -= c.orig.bounds.Pos
+	bounds.Pos -= c.orig.borders.Pos
 	bx, by, bw, bh := intBounds(bounds)
 	glhf.Bounds(bx, by, bw, bh)
 }
@@ -274,7 +278,7 @@ func (c *Canvas) Color(at pixel.Vec) pixel.NRGBA {
 	if !c.bounds.Contains(at) {
 		return pixel.NRGBA{}
 	}
-	bx, by, bw, _ := intBounds(c.orig.bounds)
+	bx, by, bw, _ := intBounds(c.orig.borders)
 	x, y := int(at.X())-bx, int(at.Y())-by
 	off := y*bw + x
 	return pixel.NRGBA{
@@ -433,7 +437,7 @@ func (ccp *canvasCanvasPicture) Draw(t pixel.TargetTriangles) {
 	if ccp.dst != ct.dst {
 		panic(fmt.Errorf("%T.Draw: TargetTriangles generated by different Canvas", ccp))
 	}
-	ct.draw(ccp.src.f.Texture(), ccp.src.orig.bounds, ccp.bounds)
+	ct.draw(ccp.src.f.Texture(), ccp.src.orig.borders, ccp.bounds)
 }
 
 const (