Skip to content

Commit

Permalink
internal/ui: bug fix: need to sleep when swapping buffers is skipped
Browse files Browse the repository at this point in the history
Closes #2890
  • Loading branch information
hajimehoshi committed Jan 24, 2024
1 parent 3be6c78 commit 256d403
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 18 deletions.
20 changes: 2 additions & 18 deletions internal/graphicsdriver/metal/graphics_darwin.go
Expand Up @@ -20,7 +20,6 @@ import (
"math"
"runtime"
"sort"
"time"
"unsafe"

"github.com/ebitengine/purego/objc"
Expand Down Expand Up @@ -62,8 +61,6 @@ type Graphics struct {
maxImageSize int
tmpTextures []mtl.Texture

lastFlush time.Time

pool cocoa.NSAutoreleasePool
}

Expand Down Expand Up @@ -230,25 +227,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)
Expand Down
10 changes: 10 additions & 0 deletions internal/ui/context.go
Expand Up @@ -17,6 +17,7 @@ package ui
import (
"math"
"sync"
"time"

"github.com/hajimehoshi/ebiten/v2/internal/atlas"
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
Expand Down Expand Up @@ -56,6 +57,7 @@ type context struct {
offscreenHeight float64

isOffscreenModified bool
lastDrawTime time.Time

skipCount int

Expand Down Expand Up @@ -203,6 +205,11 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics, forceDraw boo
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).
Expand All @@ -214,6 +221,9 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics, forceDraw boo
// 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
Expand Down

0 comments on commit 256d403

Please sign in to comment.