diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 98960248cf04..2d7c2948a99b 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -20,7 +20,6 @@ import ( "math" "runtime" "sort" - "time" "unsafe" "github.com/ebitengine/purego/objc" @@ -62,8 +61,6 @@ type Graphics struct { maxImageSize int tmpTextures []mtl.Texture - lastFlush time.Time - pool cocoa.NSAutoreleasePool } @@ -231,25 +228,12 @@ func (g *Graphics) flushIfNeeded(present bool) { return } - now := time.Now() - defer func() { - g.lastFlush = now - }() - g.flushRenderCommandEncoderIfNeeded() if present { // This check is necessary when skipping to render the screen (SetScreenClearedEveryFrame(false)). - if g.screenDrawable == (ca.MetalDrawable{}) { - if g.cb != (mtl.CommandBuffer{}) { - g.screenDrawable = g.view.nextDrawable() - } else { - if delta := time.Second/60 - now.Sub(g.lastFlush); delta > 0 { - // nextDrawable can return immediately when the command buffer is empty. - // To avoid high CPU usage, sleep instead (#2520). - time.Sleep(delta) - } - } + if g.screenDrawable == (ca.MetalDrawable{}) && g.cb != (mtl.CommandBuffer{}) { + g.screenDrawable = g.view.nextDrawable() } if g.screenDrawable != (ca.MetalDrawable{}) { g.cb.PresentDrawable(g.screenDrawable) diff --git a/internal/ui/context.go b/internal/ui/context.go index c4cd4a131493..7abcf395a3b1 100644 --- a/internal/ui/context.go +++ b/internal/ui/context.go @@ -16,6 +16,7 @@ package ui import ( "math" + "time" "github.com/hajimehoshi/ebiten/v2/internal/atlas" "github.com/hajimehoshi/ebiten/v2/internal/clock" @@ -53,6 +54,7 @@ type context struct { offscreenHeight float64 isOffscreenModified bool + lastDrawTime time.Time skipCount int } @@ -198,6 +200,11 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics, ui *UserInter c.skipCount = 0 } + now := time.Now() + defer func() { + c.lastDrawTime = now + }() + if c.skipCount < maxSkipCount { if graphicsDriver.NeedsClearingScreen() { // This clear is needed for fullscreen mode or some mobile platforms (#622). @@ -209,6 +216,9 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics, ui *UserInter // The final screen is never used as the rendering source. // Flush its buffer here just in case. c.screen.flushBufferIfNeeded() + } else if delta := time.Second/60 - now.Sub(c.lastDrawTime); delta > 0 { + // When swapping buffers is skipped and Draw is called too early, sleep for a while to suppress CPU usages (#2890). + time.Sleep(delta) } return nil