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 (
"math"
"sync/atomic"
"github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
"github.com/hajimehoshi/ebiten/internal/ui"
)
func newGraphicsContext(f func(*Image) error) *graphicsContext {
@ -33,7 +35,14 @@ type graphicsContext struct {
offscreen2 *Image // TODO: better name
screen *Image
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 {
@ -82,11 +91,11 @@ func (c *graphicsContext) needsRestoring(context *opengl.Context) (bool, 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 {
return err
}
c.initialized = true
atomic.StoreInt32(&c.initialized, 1)
}
r, err := c.needsRestoring(context)
if err != nil {

View File

@ -21,9 +21,20 @@ import (
"sync"
"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 {
images map[*imageImpl]struct{}
m sync.Mutex
@ -141,7 +152,7 @@ func (i *Image) Size() (width, height int) {
//
// This function is concurrent-safe.
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 i.impl.Fill(color.Transparent)
@ -151,7 +162,7 @@ func (i *Image) Clear() error {
//
// This function is concurrent-safe.
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 i.impl.Fill(clr)
@ -174,7 +185,7 @@ func (i *Image) Fill(clr color.Color) error {
//
// This function is concurrent-safe.
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 i.impl.DrawImage(image, options)
@ -202,7 +213,7 @@ func (i *Image) ColorModel() color.Model {
//
// This function is concurrent-safe.
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.
@ -212,7 +223,7 @@ func (i *Image) At(x, y int) color.Color {
//
// This function is concurrent-safe.
func (i *Image) Dispose() error {
if err := theImagesForRestoring.flushPixelsIfNeeded(i, ui.GLContext()); err != nil {
if err := theImagesForRestoring.flushPixelsIfNeeded(i, glContext()); err != nil {
return err
}
if i.impl.isDisposed() {
@ -229,7 +240,7 @@ func (i *Image) Dispose() error {
//
// This function is concurrent-safe.
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 i.impl.ReplacePixels(p)

4
run.go
View File

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