internal/ui: bug fix: need to sleep when swapping buffers is skipped

Closes #2890
This commit is contained in:
Hajime Hoshi 2024-01-24 12:01:26 +09:00
parent 006f14ac19
commit 8551cd350f
2 changed files with 12 additions and 18 deletions

View File

@ -20,7 +20,6 @@ import (
"math" "math"
"runtime" "runtime"
"sort" "sort"
"time"
"unsafe" "unsafe"
"github.com/ebitengine/purego/objc" "github.com/ebitengine/purego/objc"
@ -62,8 +61,6 @@ type Graphics struct {
maxImageSize int maxImageSize int
tmpTextures []mtl.Texture tmpTextures []mtl.Texture
lastFlush time.Time
pool cocoa.NSAutoreleasePool pool cocoa.NSAutoreleasePool
} }
@ -231,25 +228,12 @@ func (g *Graphics) flushIfNeeded(present bool) {
return return
} }
now := time.Now()
defer func() {
g.lastFlush = now
}()
g.flushRenderCommandEncoderIfNeeded() g.flushRenderCommandEncoderIfNeeded()
if present { if present {
// This check is necessary when skipping to render the screen (SetScreenClearedEveryFrame(false)). // This check is necessary when skipping to render the screen (SetScreenClearedEveryFrame(false)).
if g.screenDrawable == (ca.MetalDrawable{}) { if g.screenDrawable == (ca.MetalDrawable{}) && g.cb != (mtl.CommandBuffer{}) {
if g.cb != (mtl.CommandBuffer{}) {
g.screenDrawable = g.view.nextDrawable() 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{}) { if g.screenDrawable != (ca.MetalDrawable{}) {
g.cb.PresentDrawable(g.screenDrawable) g.cb.PresentDrawable(g.screenDrawable)

View File

@ -16,6 +16,7 @@ package ui
import ( import (
"math" "math"
"time"
"github.com/hajimehoshi/ebiten/v2/internal/atlas" "github.com/hajimehoshi/ebiten/v2/internal/atlas"
"github.com/hajimehoshi/ebiten/v2/internal/clock" "github.com/hajimehoshi/ebiten/v2/internal/clock"
@ -53,6 +54,7 @@ type context struct {
offscreenHeight float64 offscreenHeight float64
isOffscreenModified bool isOffscreenModified bool
lastDrawTime time.Time
skipCount int skipCount int
} }
@ -198,6 +200,11 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics, ui *UserInter
c.skipCount = 0 c.skipCount = 0
} }
now := time.Now()
defer func() {
c.lastDrawTime = now
}()
if c.skipCount < maxSkipCount { if c.skipCount < maxSkipCount {
if graphicsDriver.NeedsClearingScreen() { if graphicsDriver.NeedsClearingScreen() {
// This clear is needed for fullscreen mode or some mobile platforms (#622). // 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. // The final screen is never used as the rendering source.
// Flush its buffer here just in case. // Flush its buffer here just in case.
c.screen.flushBufferIfNeeded() 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 return nil