buffered: Defer filling an image

This change defers filling an image so that successive fillings
can be merged into one for more efficient rendering.

Fixes #1134
This commit is contained in:
Hajime Hoshi 2020-04-18 02:11:23 +09:00
parent 514c3faebd
commit bbeb0d14e6

View File

@ -29,6 +29,9 @@ type Image struct {
width int
height int
hasFill bool
fillColor color.RGBA
pixels []byte
needsToResolvePixels bool
}
@ -92,18 +95,29 @@ func (i *Image) initializeAsScreenFramebuffer(width, height int) {
func (i *Image) invalidatePendingPixels() {
i.pixels = nil
i.needsToResolvePixels = false
i.hasFill = false
}
func (i *Image) resolvePendingPixels(keepPendingPixels bool) {
if !i.needsToResolvePixels {
if i.needsToResolvePixels && i.hasFill {
panic("buffered: needsToResolvePixels and hasFill must not be true at the same time")
}
if i.needsToResolvePixels {
i.img.ReplacePixels(i.pixels)
if !keepPendingPixels {
i.pixels = nil
}
i.needsToResolvePixels = false
}
i.resolvePendingFill()
}
func (i *Image) resolvePendingFill() {
if !i.hasFill {
return
}
i.img.ReplacePixels(i.pixels)
if !keepPendingPixels {
i.pixels = nil
}
i.needsToResolvePixels = false
i.img.Fill(i.fillColor)
i.hasFill = false
}
func (i *Image) MarkDisposed() {
@ -127,8 +141,12 @@ func (i *Image) At(x, y int) (r, g, b, a byte, err error) {
if needsToDelayCommands {
panic("buffered: the command queue is not available yet at At")
}
// If there are pixels that needs to be resolved, use this rather than resolving. Resolving pixels needs
// to access GPU and is expensive (#1137).
// If there are pixels or pending fillling that needs to be resolved, use this rather than resolving.
// Resolving them needs to access GPU and is expensive (#1137).
if i.hasFill {
return i.fillColor.R, i.fillColor.G, i.fillColor.B, i.fillColor.A, nil
}
if i.pixels != nil {
idx := i.width*y + x
return i.pixels[4*idx], i.pixels[4*idx+1], i.pixels[4*idx+2], i.pixels[4*idx+3], nil
@ -157,8 +175,10 @@ func (i *Image) Fill(clr color.RGBA) {
return
}
// Defer filling the image so that successive fillings will be merged into one (#1134).
i.invalidatePendingPixels()
i.img.Fill(clr)
i.fillColor = clr
i.hasFill = true
}
func (i *Image) ReplacePixels(pix []byte, x, y, width, height int) error {
@ -179,6 +199,8 @@ func (i *Image) ReplacePixels(pix []byte, x, y, width, height int) error {
return nil
}
i.resolvePendingFill()
if x == 0 && y == 0 && width == i.width && height == i.height {
i.invalidatePendingPixels()
i.img.ReplacePixels(pix)