graphics: Bug fix: GL context is not available until graphics context is initialized

This commit is contained in:
Hajime Hoshi 2016-07-24 06:02:04 +09:00
parent e118a755f5
commit 9bbd5e89c3
3 changed files with 34 additions and 10 deletions

View File

@ -16,9 +16,11 @@ package ebiten
import ( import (
"math" "math"
"sync/atomic"
"github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/graphics/opengl" "github.com/hajimehoshi/ebiten/internal/graphics/opengl"
"github.com/hajimehoshi/ebiten/internal/ui"
) )
func newGraphicsContext(f func(*Image) error) *graphicsContext { func newGraphicsContext(f func(*Image) error) *graphicsContext {
@ -33,7 +35,14 @@ type graphicsContext struct {
offscreen2 *Image // TODO: better name offscreen2 *Image // TODO: better name
screen *Image screen *Image
screenScale float64 screenScale float64
initialized bool initialized int32
}
func (c *graphicsContext) GLContext() *opengl.Context {
if atomic.LoadInt32(&c.initialized) == 0 {
return nil
}
return ui.GLContext()
} }
func (c *graphicsContext) SetSize(screenWidth, screenHeight int, screenScale float64) error { func (c *graphicsContext) SetSize(screenWidth, screenHeight int, screenScale float64) error {
@ -82,11 +91,11 @@ func (c *graphicsContext) needsRestoring(context *opengl.Context) (bool, error)
} }
func (c *graphicsContext) initializeIfNeeded(context *opengl.Context) error { func (c *graphicsContext) initializeIfNeeded(context *opengl.Context) error {
if !c.initialized { if atomic.LoadInt32(&c.initialized) == 0 {
if err := graphics.Reset(context); err != nil { if err := graphics.Reset(context); err != nil {
return err return err
} }
c.initialized = true atomic.StoreInt32(&c.initialized, 1)
} }
r, err := c.needsRestoring(context) r, err := c.needsRestoring(context)
if err != nil { if err != nil {

View File

@ -21,9 +21,20 @@ import (
"sync" "sync"
"github.com/hajimehoshi/ebiten/internal/graphics/opengl" "github.com/hajimehoshi/ebiten/internal/graphics/opengl"
"github.com/hajimehoshi/ebiten/internal/ui"
) )
func glContext() *opengl.Context {
// This is called from finalizers even when the context or the program is not set.
g, ok := theGraphicsContext.Load().(*graphicsContext)
if !ok {
return nil
}
if g == nil {
return nil
}
return g.GLContext()
}
type images struct { type images struct {
images map[*imageImpl]struct{} images map[*imageImpl]struct{}
m sync.Mutex m sync.Mutex
@ -141,7 +152,7 @@ func (i *Image) Size() (width, height int) {
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func (i *Image) Clear() error { func (i *Image) Clear() error {
if err := theImagesForRestoring.flushPixelsIfNeeded(i, ui.GLContext()); err != nil { if err := theImagesForRestoring.flushPixelsIfNeeded(i, glContext()); err != nil {
return err return err
} }
return i.impl.Fill(color.Transparent) return i.impl.Fill(color.Transparent)
@ -151,7 +162,7 @@ func (i *Image) Clear() error {
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func (i *Image) Fill(clr color.Color) error { func (i *Image) Fill(clr color.Color) error {
if err := theImagesForRestoring.flushPixelsIfNeeded(i, ui.GLContext()); err != nil { if err := theImagesForRestoring.flushPixelsIfNeeded(i, glContext()); err != nil {
return err return err
} }
return i.impl.Fill(clr) return i.impl.Fill(clr)
@ -174,7 +185,7 @@ func (i *Image) Fill(clr color.Color) error {
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func (i *Image) DrawImage(image *Image, options *DrawImageOptions) error { func (i *Image) DrawImage(image *Image, options *DrawImageOptions) error {
if err := theImagesForRestoring.flushPixelsIfNeeded(i, ui.GLContext()); err != nil { if err := theImagesForRestoring.flushPixelsIfNeeded(i, glContext()); err != nil {
return err return err
} }
return i.impl.DrawImage(image, options) return i.impl.DrawImage(image, options)
@ -202,7 +213,7 @@ func (i *Image) ColorModel() color.Model {
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func (i *Image) At(x, y int) color.Color { func (i *Image) At(x, y int) color.Color {
return i.impl.At(x, y, ui.GLContext()) return i.impl.At(x, y, glContext())
} }
// Dispose disposes the image data. After disposing, the image becomes invalid. // Dispose disposes the image data. After disposing, the image becomes invalid.
@ -212,7 +223,7 @@ func (i *Image) At(x, y int) color.Color {
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func (i *Image) Dispose() error { func (i *Image) Dispose() error {
if err := theImagesForRestoring.flushPixelsIfNeeded(i, ui.GLContext()); err != nil { if err := theImagesForRestoring.flushPixelsIfNeeded(i, glContext()); err != nil {
return err return err
} }
if i.impl.isDisposed() { if i.impl.isDisposed() {
@ -229,7 +240,7 @@ func (i *Image) Dispose() error {
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func (i *Image) ReplacePixels(p []uint8) error { func (i *Image) ReplacePixels(p []uint8) error {
if err := theImagesForRestoring.flushPixelsIfNeeded(i, ui.GLContext()); err != nil { if err := theImagesForRestoring.flushPixelsIfNeeded(i, glContext()); err != nil {
return err return err
} }
return i.impl.ReplacePixels(p) return i.impl.ReplacePixels(p)

4
run.go
View File

@ -57,6 +57,8 @@ func IsRunningSlowly() bool {
return atomic.LoadInt32(&isRunningSlowly) != 0 return atomic.LoadInt32(&isRunningSlowly) != 0
} }
var theGraphicsContext atomic.Value
// Run runs the game. // Run runs the game.
// f is a function which is called at every frame. // f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen. // The argument (*Image) is the render target that represents the screen.
@ -73,6 +75,7 @@ func Run(f func(*Image) error, width, height int, scale float64, title string) e
ch := make(chan error) ch := make(chan error)
go func() { go func() {
g := newGraphicsContext(f) g := newGraphicsContext(f)
theGraphicsContext.Store(g)
if err := loop.Run(g, width, height, scale, title, FPS); err != nil { if err := loop.Run(g, width, height, scale, title, FPS); err != nil {
ch <- err ch <- err
} }
@ -93,6 +96,7 @@ func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64,
ch := make(chan error) ch := make(chan error)
go func() { go func() {
g := newGraphicsContext(f) g := newGraphicsContext(f)
theGraphicsContext.Store(g)
if err := loop.Run(g, width, height, scale, title, FPS); err != nil { if err := loop.Run(g, width, height, scale, title, FPS); err != nil {
ch <- err ch <- err
} }