diff --git a/internal/buffered/command.go b/internal/buffered/command.go index 92a3f02e5..95105cffb 100644 --- a/internal/buffered/command.go +++ b/internal/buffered/command.go @@ -19,40 +19,26 @@ import ( ) var ( - delayedCommandsFlushable bool + needsToDelayCommands = true // delayedCommands represents a queue for image operations that are ordered before the game starts // (BeginFrame). Before the game starts, the package shareable doesn't determine the minimum/maximum texture // sizes (#879). - // - // TODO: Flush the commands only when necessary (#921). delayedCommands []func() delayedCommandsM sync.Mutex ) -func makeDelayedCommandFlushable() { - delayedCommandsM.Lock() - delayedCommandsFlushable = true - delayedCommandsM.Unlock() -} - -func enqueueDelayedCommand(f func()) { - delayedCommandsM.Lock() - delayedCommands = append(delayedCommands, f) - delayedCommandsM.Unlock() -} - -func flushDelayedCommands() bool { +func flushDelayedCommands() { delayedCommandsM.Lock() defer delayedCommandsM.Unlock() - if !delayedCommandsFlushable { - return false + if !needsToDelayCommands { + return } for _, c := range delayedCommands { c() } delayedCommands = delayedCommands[:0] - return true + needsToDelayCommands = false } diff --git a/internal/buffered/image.go b/internal/buffered/image.go index 540610633..e219c18b7 100644 --- a/internal/buffered/image.go +++ b/internal/buffered/image.go @@ -30,77 +30,130 @@ func BeginFrame() error { if err := shareable.BeginFrame(); err != nil { return err } - makeDelayedCommandFlushable() - + flushDelayedCommands() return nil } func EndFrame() error { - if !flushDelayedCommands() { - panic("buffered: the command queue must be available at EndFrame") - } return shareable.EndFrame() } func NewImage(width, height int, volatile bool) *Image { i := &Image{} - enqueueDelayedCommand(func() { - i.img = shareable.NewImage(width, height, volatile) - }) + delayedCommandsM.Lock() + if needsToDelayCommands { + delayedCommands = append(delayedCommands, func() { + i.img = shareable.NewImage(width, height, volatile) + }) + delayedCommandsM.Unlock() + return i + } + delayedCommandsM.Unlock() + + i.img = shareable.NewImage(width, height, volatile) return i } func NewScreenFramebufferImage(width, height int) *Image { i := &Image{} - enqueueDelayedCommand(func() { - i.img = shareable.NewScreenFramebufferImage(width, height) - }) + delayedCommandsM.Lock() + if needsToDelayCommands { + delayedCommands = append(delayedCommands, func() { + i.img = shareable.NewScreenFramebufferImage(width, height) + }) + delayedCommandsM.Unlock() + return i + } + delayedCommandsM.Unlock() + + i.img = shareable.NewScreenFramebufferImage(width, height) return i } func (i *Image) MarkDisposed() { - enqueueDelayedCommand(func() { - i.img.MarkDisposed() - }) + delayedCommandsM.Lock() + if needsToDelayCommands { + delayedCommands = append(delayedCommands, func() { + i.img.MarkDisposed() + }) + } + delayedCommandsM.Unlock() } func (i *Image) At(x, y int) (r, g, b, a byte) { - if !flushDelayedCommands() { + delayedCommandsM.Lock() + defer delayedCommandsM.Unlock() + if needsToDelayCommands { panic("buffered: the command queue is not available yet at At") } return i.img.At(x, y) } func (i *Image) Dump(name string) error { - if !flushDelayedCommands() { + delayedCommandsM.Lock() + defer delayedCommandsM.Unlock() + if needsToDelayCommands { panic("buffered: the command queue is not available yet at Dump") } return i.img.Dump(name) } func (i *Image) Fill(clr color.RGBA) { - enqueueDelayedCommand(func() { - i.img.Fill(clr) - }) + delayedCommandsM.Lock() + if needsToDelayCommands { + delayedCommands = append(delayedCommands, func() { + i.img.Fill(clr) + }) + delayedCommandsM.Unlock() + return + } + delayedCommandsM.Unlock() + + i.img.Fill(clr) } func (i *Image) ClearFramebuffer() { - enqueueDelayedCommand(func() { - i.img.ClearFramebuffer() - }) + delayedCommandsM.Lock() + if needsToDelayCommands { + delayedCommands = append(delayedCommands, func() { + i.img.ClearFramebuffer() + }) + delayedCommandsM.Unlock() + return + } + delayedCommandsM.Unlock() + + i.img.ClearFramebuffer() } func (i *Image) ReplacePixels(pix []byte) { - enqueueDelayedCommand(func() { - i.img.ReplacePixels(pix) - }) + delayedCommandsM.Lock() + if needsToDelayCommands { + delayedCommands = append(delayedCommands, func() { + i.img.ReplacePixels(pix) + }) + delayedCommandsM.Unlock() + return + } + delayedCommandsM.Unlock() + + i.img.ReplacePixels(pix) } func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address) { if i == src { panic("buffered: Image.DrawTriangles: src must be different from the receiver") } - enqueueDelayedCommand(func() { - i.img.DrawTriangles(src.img, vertices, indices, colorm, mode, filter, address) - }) + + delayedCommandsM.Lock() + if needsToDelayCommands { + delayedCommands = append(delayedCommands, func() { + i.img.DrawTriangles(src.img, vertices, indices, colorm, mode, filter, address) + }) + delayedCommandsM.Unlock() + return + } + delayedCommandsM.Unlock() + + i.img.DrawTriangles(src.img, vertices, indices, colorm, mode, filter, address) }