From 4824dc036072f0801f5fd3862b58f58140803945 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 8 Sep 2024 12:56:42 +0900 Subject: [PATCH] internal/restorable: resolve a stale state when possible --- image.go | 35 +++++++++++++++++++++++++++++++++-- internal/restorable/image.go | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/image.go b/image.go index bf2235636..0b0a5b611 100644 --- a/image.go +++ b/image.go @@ -267,7 +267,31 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) { }) } - i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, canSkipMipmap(geoM, filter), false, restorable.HintNone) + dr := i.adjustedBounds() + hint := restorable.HintNone + if overwritesDstRegion(options.Blend, dr, geoM, sx0, sy0, sx1, sy1) { + hint = restorable.HintOverwriteDstRegion + } + + i.image.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, canSkipMipmap(geoM, filter), false, hint) +} + +// overwritesDstRegion reports whether the given parameters overwrite the destination region completely. +func overwritesDstRegion(blend Blend, dstRegion image.Rectangle, geoM GeoM, sx0, sy0, sx1, sy1 int) bool { + if blend != BlendCopy { + return false + } + // Check the result vertices is not a rotated rectangle. + if geoM.b != 0 || geoM.c != 0 { + return false + } + // Check the result vertices completely covers dstRegion. + x0, y0 := geoM.Apply(float64(sx0), float64(sy0)) + x1, y1 := geoM.Apply(float64(sx1), float64(sy1)) + if float64(dstRegion.Min.X) < x0 || float64(dstRegion.Min.Y) < y0 || float64(dstRegion.Max.X) > x1 || float64(dstRegion.Max.Y) > y1 { + return false + } + return true } // Vertex represents a vertex passed to DrawTriangles. @@ -856,7 +880,14 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR i.tmpUniforms = i.tmpUniforms[:0] i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms) - i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, true, false, restorable.HintNone) + dr := i.adjustedBounds() + hint := restorable.HintNone + // Do not use srcRegions[0].Dx() and srcRegions[0].Dy() as these might be empty. + if overwritesDstRegion(options.Blend, dr, geoM, srcRegions[0].Min.X, srcRegions[0].Min.Y, srcRegions[0].Min.X+width, srcRegions[0].Min.Y+height) { + hint = restorable.HintOverwriteDstRegion + } + + i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, true, false, hint) } // SubImage returns an image representing the portion of the image p visible through r. diff --git a/internal/restorable/image.go b/internal/restorable/image.go index eb9bab33c..232ddaab7 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -347,10 +347,25 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice } // Even if the image is already stale, call makeStale to extend the stale region. - if srcstale || !needsRestoration() || !i.needsRestoration() || i.stale { + if srcstale || !needsRestoration() || !i.needsRestoration() { i.makeStale(dstRegion) - } else { - // TODO: Consider overwritten. + } else if i.stale { + var overwrite bool + if hint == HintOverwriteDstRegion { + overwrite = i.areStaleRegionsIncludedIn(dstRegion) + } + if overwrite { + i.basePixels.Clear(dstRegion) + i.clearDrawTrianglesHistory() + i.stale = false + i.staleRegions = i.staleRegions[:0] + } else { + // Even if the image is already stale, call makeStale to extend the stale region. + i.makeStale(dstRegion) + } + } + + if !i.stale { i.appendDrawTrianglesHistory(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, hint) } @@ -364,6 +379,18 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice i.image.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule) } +func (i *Image) areStaleRegionsIncludedIn(r image.Rectangle) bool { + if !i.stale { + return false + } + for _, sr := range i.staleRegions { + if !sr.In(r) { + return false + } + } + return true +} + // appendDrawTrianglesHistory appends a draw-image history item to the image. func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, hint Hint) { if i.stale || !i.needsRestoration() {