internal/graphicsdriver: bug fix: stop recreating CAMetalDisplayLink after sleep

This change fixes the issue where an app freezes after waking up from
sleep.

Apparently, recreating CAMetalDisplayLink is not necessary.

Updates #3353
This commit is contained in:
Hajime Hoshi
2025-12-04 13:48:48 +09:00
parent 3cf2994c3b
commit 09eebf6cf5
2 changed files with 4 additions and 37 deletions

View File

@@ -71,7 +71,6 @@ func (v *view) initCAMetalDisplayLink() error {
v.drawableCh = make(chan ca.MetalDrawable)
v.drawableDoneCh = make(chan struct{})
v.metalDisplayLinkRunLoop = createThreadWithRunLoop()
v.prevMetalDisplayLink = make(chan uintptr, 1)
c, err := objc.RegisterClass(
"EbitengineCAMetalDisplayLinkDelegate",
@@ -99,37 +98,10 @@ func (v *view) initCAMetalDisplayLink() error {
v.createCAMetalDisplayLink()
// Recreate the display link when the app is recovered from sleep.
// TODO: Recreation might be needed when the display is changed.
nc := cocoa.NSWorkspace_sharedWorkspace().NotificationCenter()
if v.meltaDisplayLinkRecreateBlock == 0 {
v.meltaDisplayLinkRecreateBlock = objc.NewBlock(func(block objc.Block) {
v.createCAMetalDisplayLink()
})
}
mainQueue := cocoa.NSOperationQueue_mainQueue()
v.notificatioObserver = nc.AddObserverForName(cocoa.NSWorkspaceDidWakeNotification, 0, mainQueue, v.meltaDisplayLinkRecreateBlock)
cocoa.NSObject{ID: v.notificatioObserver}.Retain()
return nil
}
func (v *view) createCAMetalDisplayLink() {
// Release the previous display link if any.
// This is done in the thread for the display link, so that the callback is not called during releasing.
if v.metalDisplayLink != 0 {
// Unfortunately, there is no blocking 'performBlock' for NSRunLoop, so use a channel to wait.
if v.metalDisplayLinkReleaseBlock == 0 {
v.metalDisplayLinkReleaseBlock = objc.NewBlock(func(block objc.Block) {
dl := ca.MetalDisplayLink{ID: objc.ID(<-v.prevMetalDisplayLink)}
dl.RemoveFromRunLoop(v.metalDisplayLinkRunLoop, cocoa.NSDefaultRunLoopMode)
dl.Release()
})
}
v.prevMetalDisplayLink <- v.metalDisplayLink
v.metalDisplayLinkRunLoop.PerformBlock(v.metalDisplayLinkReleaseBlock)
}
ch := make(chan uintptr)
v.metalDisplayLinkRunLoop.PerformBlock(objc.NewBlock(func(block objc.Block) {
dl := ca.NewMetalDisplayLink(v.ml)

View File

@@ -20,7 +20,6 @@ import (
"sync"
"time"
"github.com/ebitengine/purego/objc"
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
"github.com/hajimehoshi/ebiten/v2/internal/color"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca"
@@ -49,14 +48,10 @@ type view struct {
metalDisplayLink uintptr
// The following members are used only with CAMetalDisplayLink.
drawableCh chan ca.MetalDrawable
drawableDoneCh chan struct{}
drawableTimer *time.Timer
prevMetalDisplayLink chan uintptr
notificatioObserver objc.ID
metalDisplayLinkRunLoop cocoa.NSRunLoop
metalDisplayLinkReleaseBlock objc.Block
meltaDisplayLinkRecreateBlock objc.Block
drawableCh chan ca.MetalDrawable
drawableDoneCh chan struct{}
drawableTimer *time.Timer
metalDisplayLinkRunLoop cocoa.NSRunLoop
// The following members are used only with CADisplayLink.
handleToSelf cgo.Handle