mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
internal/ui: refactoring
This commit is contained in:
parent
2eca476054
commit
f2acc3d9f7
@ -59,13 +59,13 @@ type context struct {
|
|||||||
|
|
||||||
setContextOnce sync.Once
|
setContextOnce sync.Once
|
||||||
|
|
||||||
deferred []func()
|
funcsInFrameCh chan func()
|
||||||
deferredM sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContext(game Game) *context {
|
func newContext(game Game) *context {
|
||||||
return &context{
|
return &context{
|
||||||
game: game,
|
game: game,
|
||||||
|
funcsInFrameCh: make(chan func()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,8 +118,8 @@ func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, update
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Flush deferred functions, like reading pixels from GPU.
|
// Flush deferred functions, like reading pixels from GPU.
|
||||||
if err := c.flushDeferredFuncs(ui); err != nil {
|
if err := c.processFuncsInFrame(ui); err != nil {
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForceUpdate can be invoked even if the context is not initialized yet (#1591).
|
// ForceUpdate can be invoked even if the context is not initialized yet (#1591).
|
||||||
@ -297,30 +297,31 @@ func (u *UserInterface) LogicalPositionToClientPosition(x, y float64) (float64,
|
|||||||
return u.context.logicalPositionToClientPosition(x, y, u.DeviceScaleFactor())
|
return u.context.logicalPositionToClientPosition(x, y, u.DeviceScaleFactor())
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendDeferredFunc appends a function.
|
func (c *context) runInFrame(f func()) {
|
||||||
// An appended function is called at the next frame.
|
ch := make(chan struct{})
|
||||||
func (c *context) appendDeferredFunc(f func()) {
|
c.funcsInFrameCh <- func() {
|
||||||
c.deferredM.Lock()
|
defer close(ch)
|
||||||
defer c.deferredM.Unlock()
|
|
||||||
c.deferred = append(c.deferred, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *context) flushDeferredFuncs(ui *UserInterface) error {
|
|
||||||
c.deferredM.Lock()
|
|
||||||
fs := c.deferred
|
|
||||||
c.deferred = nil
|
|
||||||
c.deferredM.Unlock()
|
|
||||||
|
|
||||||
for _, f := range fs {
|
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
<-ch
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(fs) > 0 {
|
func (c *context) processFuncsInFrame(ui *UserInterface) error {
|
||||||
// Catch the error that happened at (*Image).At.
|
var processed bool
|
||||||
if err := ui.error(); err != nil {
|
for {
|
||||||
return err
|
select {
|
||||||
|
case f := <-c.funcsInFrameCh:
|
||||||
|
f()
|
||||||
|
processed = true
|
||||||
|
default:
|
||||||
|
if processed {
|
||||||
|
// Catch the error that happened at (*Image).At.
|
||||||
|
if err := ui.error(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -128,12 +128,16 @@ func (u *UserInterface) readPixels(mipmap *mipmap.Mipmap, pixels []byte, region
|
|||||||
// ReadPixels failed since this was called in between two frames.
|
// ReadPixels failed since this was called in between two frames.
|
||||||
// Try this again at the next frame.
|
// Try this again at the next frame.
|
||||||
if !ok {
|
if !ok {
|
||||||
ch := make(chan error)
|
// If this function is called from the same sequence as a game's Update and Draw,
|
||||||
u.context.appendDeferredFunc(func() {
|
// this causes a dead lock.
|
||||||
defer close(ch)
|
// This never happens so far, but if handling inputs after EndFrame is implemented,
|
||||||
|
// this might be possible (#1704).
|
||||||
|
|
||||||
|
var err1 error
|
||||||
|
u.context.runInFrame(func() {
|
||||||
ok, err := mipmap.ReadPixels(u.graphicsDriver, pixels, region)
|
ok, err := mipmap.ReadPixels(u.graphicsDriver, pixels, region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ch <- err
|
err1 = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -141,12 +145,7 @@ func (u *UserInterface) readPixels(mipmap *mipmap.Mipmap, pixels []byte, region
|
|||||||
panic("ui: ReadPixels unexpectedly failed")
|
panic("ui: ReadPixels unexpectedly failed")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return err1
|
||||||
// If this function is called from the game (Update/Draw) goroutine in between two frames,
|
|
||||||
// this channel never returns and causes a dead lock.
|
|
||||||
// This never happens so far, but if handling inputs after EndFrame is implemented,
|
|
||||||
// this might be possible (#1704).
|
|
||||||
return <-ch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user