diff --git a/graphicscontext.go b/graphicscontext.go index d68cd924f..90c4e8e18 100644 --- a/graphicscontext.go +++ b/graphicscontext.go @@ -16,12 +16,9 @@ package ebiten import ( "math" - "sync/atomic" "github.com/hajimehoshi/ebiten/internal/graphics" - "github.com/hajimehoshi/ebiten/internal/opengl" "github.com/hajimehoshi/ebiten/internal/restorable" - "github.com/hajimehoshi/ebiten/internal/ui" ) func newGraphicsContext(f func(*Image) error) *graphicsContext { @@ -36,17 +33,10 @@ type graphicsContext struct { offscreen2 *Image // TODO: better name screen *Image screenScale float64 - initialized int32 + initialized bool invalidated bool // browser only } -func (c *graphicsContext) GLContext() *opengl.Context { - if atomic.LoadInt32(&c.initialized) == 0 { - return nil - } - return ui.GLContext() -} - func (c *graphicsContext) Invalidate() { // Note that this is called only on browsers so far. // TODO: On mobiles, this function is not called and instead IsTexture is called @@ -100,21 +90,21 @@ func (c *graphicsContext) SetSize(screenWidth, screenHeight int, screenScale flo return nil } -func (c *graphicsContext) initializeIfNeeded(context *opengl.Context) error { - if atomic.LoadInt32(&c.initialized) == 0 { - if err := graphics.Reset(context); err != nil { +func (c *graphicsContext) initializeIfNeeded() error { + if !c.initialized { + if err := graphics.Reset(); err != nil { return err } - atomic.StoreInt32(&c.initialized, 1) + c.initialized = true } - r, err := c.needsRestoring(context) + r, err := c.needsRestoring() if err != nil { return err } if !r { return nil } - if err := c.restore(context); err != nil { + if err := c.restore(); err != nil { return err } return nil @@ -130,17 +120,17 @@ func drawWithFittingScale(dst *Image, src *Image) { _ = dst.DrawImage(src, op) } -func (c *graphicsContext) drawToDefaultRenderTarget(context *opengl.Context) error { +func (c *graphicsContext) drawToDefaultRenderTarget() error { _ = c.screen.Clear() drawWithFittingScale(c.screen, c.offscreen2) - if err := graphics.FlushCommands(context); err != nil { + if err := graphics.FlushCommands(); err != nil { return err } return nil } -func (c *graphicsContext) UpdateAndDraw(context *opengl.Context, updateCount int) error { - if err := c.initializeIfNeeded(context); err != nil { +func (c *graphicsContext) UpdateAndDraw(updateCount int) error { + if err := c.initializeIfNeeded(); err != nil { return err } for i := 0; i < updateCount; i++ { @@ -153,21 +143,21 @@ func (c *graphicsContext) UpdateAndDraw(context *opengl.Context, updateCount int if 0 < updateCount { drawWithFittingScale(c.offscreen2, c.offscreen) } - if err := c.drawToDefaultRenderTarget(context); err != nil { + if err := c.drawToDefaultRenderTarget(); err != nil { return err } // TODO: Add tests to check if this behavior is correct (#357) - if err := restorable.ResolveStalePixels(context); err != nil { + if err := restorable.ResolveStalePixels(); err != nil { return err } return nil } -func (c *graphicsContext) restore(context *opengl.Context) error { - if err := graphics.Reset(context); err != nil { +func (c *graphicsContext) restore() error { + if err := graphics.Reset(); err != nil { return err } - if err := restorable.Restore(context); err != nil { + if err := restorable.Restore(); err != nil { return err } c.invalidated = false diff --git a/graphicscontext_js.go b/graphicscontext_js.go index a8e4b1188..b0b9a204e 100644 --- a/graphicscontext_js.go +++ b/graphicscontext_js.go @@ -16,10 +16,6 @@ package ebiten -import ( - "github.com/hajimehoshi/ebiten/internal/opengl" -) - -func (c *graphicsContext) needsRestoring(context *opengl.Context) (bool, error) { +func (c *graphicsContext) needsRestoring() (bool, error) { return c.invalidated, nil } diff --git a/graphicscontext_notjs.go b/graphicscontext_notjs.go index ef921cfc3..4032cdf0e 100644 --- a/graphicscontext_notjs.go +++ b/graphicscontext_notjs.go @@ -18,13 +18,12 @@ package ebiten import ( "github.com/hajimehoshi/ebiten/internal/graphics" - "github.com/hajimehoshi/ebiten/internal/opengl" ) -func (c *graphicsContext) needsRestoring(context *opengl.Context) (bool, error) { +func (c *graphicsContext) needsRestoring() (bool, error) { // FlushCommands is required because c.offscreen.impl might not have an actual texture. - if err := graphics.FlushCommands(context); err != nil { + if err := graphics.FlushCommands(); err != nil { return false, err } - return c.offscreen.restorable.IsInvalidated(context), nil + return c.offscreen.restorable.IsInvalidated(), nil } diff --git a/image.go b/image.go index ec787ce6f..c38715236 100644 --- a/image.go +++ b/image.go @@ -25,18 +25,6 @@ import ( "github.com/hajimehoshi/ebiten/internal/restorable" ) -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() -} - // Image represents an image. // The pixel format is alpha-premultiplied. // Image implements image.Image. @@ -166,7 +154,7 @@ func (i *Image) At(x, y int) color.Color { return color.Transparent } // TODO: Error should be delayed until flushing. Do not panic here. - clr, err := i.restorable.At(x, y, glContext()) + clr, err := i.restorable.At(x, y) if err != nil { panic(err) } diff --git a/internal/graphics/command.go b/internal/graphics/command.go index 53e9ba9b5..e398b1fad 100644 --- a/internal/graphics/command.go +++ b/internal/graphics/command.go @@ -27,7 +27,7 @@ import ( ) type command interface { - Exec(context *opengl.Context, indexOffsetInBytes int) error + Exec(indexOffsetInBytes int) error } type commandQueue struct { @@ -113,11 +113,11 @@ func (q *commandQueue) commandGroups() [][]command { return gs } -func (q *commandQueue) Flush(context *opengl.Context) error { +func (q *commandQueue) Flush() error { q.m.Lock() defer q.m.Unlock() // glViewport must be called at least at every frame on iOS. - context.ResetViewportSize() + opengl.GetContext().ResetViewportSize() n := 0 lastN := 0 for _, g := range q.commandGroups() { @@ -128,7 +128,7 @@ func (q *commandQueue) Flush(context *opengl.Context) error { } } if 0 < n-lastN { - context.BufferSubData(opengl.ArrayBuffer, q.vertices[lastN:n]) + opengl.GetContext().BufferSubData(opengl.ArrayBuffer, q.vertices[lastN:n]) } // NOTE: WebGL doesn't seem to have Check gl.MAX_ELEMENTS_VERTICES or gl.MAX_ELEMENTS_INDICES so far. // Let's use them to compare to len(quads) in the future. @@ -138,7 +138,7 @@ func (q *commandQueue) Flush(context *opengl.Context) error { numc := len(g) indexOffsetInBytes := 0 for _, c := range g { - if err := c.Exec(context, indexOffsetInBytes); err != nil { + if err := c.Exec(indexOffsetInBytes); err != nil { return err } if c, ok := c.(*drawImageCommand); ok { @@ -148,7 +148,7 @@ func (q *commandQueue) Flush(context *opengl.Context) error { } if 0 < numc { // Call glFlush to prevent black flicking (especially on Android (#226) and iOS). - context.Flush() + opengl.GetContext().Flush() } lastN = n } @@ -157,8 +157,8 @@ func (q *commandQueue) Flush(context *opengl.Context) error { return nil } -func FlushCommands(context *opengl.Context) error { - return theCommandQueue.Flush(context) +func FlushCommands() error { + return theCommandQueue.Flush() } type fillCommand struct { @@ -166,12 +166,12 @@ type fillCommand struct { color color.RGBA } -func (c *fillCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error { - f, err := c.dst.createFramebufferIfNeeded(context) +func (c *fillCommand) Exec(indexOffsetInBytes int) error { + f, err := c.dst.createFramebufferIfNeeded() if err != nil { return err } - if err := f.setAsViewport(context); err != nil { + if err := f.setAsViewport(); err != nil { return err } cr, cg, cb, ca := c.color.R, c.color.G, c.color.B, c.color.A @@ -180,7 +180,7 @@ func (c *fillCommand) Exec(context *opengl.Context, indexOffsetInBytes int) erro g := float64(cg) / max b := float64(cb) / max a := float64(ca) / max - return context.FillFramebuffer(r, g, b, a) + return opengl.GetContext().FillFramebuffer(r, g, b, a) } type drawImageCommand struct { @@ -195,15 +195,15 @@ func QuadVertexSizeInBytes() int { return 4 * theArrayBufferLayout.totalBytes() } -func (c *drawImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error { - f, err := c.dst.createFramebufferIfNeeded(context) +func (c *drawImageCommand) Exec(indexOffsetInBytes int) error { + f, err := c.dst.createFramebufferIfNeeded() if err != nil { return err } - if err := f.setAsViewport(context); err != nil { + if err := f.setAsViewport(); err != nil { return err } - context.BlendFunc(c.mode) + opengl.GetContext().BlendFunc(c.mode) n := c.quadsNum() if n == 0 { @@ -214,7 +214,6 @@ func (c *drawImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) p := &programContext{ state: &theOpenGLState, program: theOpenGLState.programTexture, - context: context, projectionMatrix: proj, texture: c.src.texture.native, colorM: c.color, @@ -224,7 +223,7 @@ func (c *drawImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) } // TODO: We should call glBindBuffer here? // The buffer is already bound at begin() but it is counterintuitive. - context.DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes) + opengl.GetContext().DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes) return nil } @@ -263,29 +262,29 @@ type replacePixelsCommand struct { pixels []uint8 } -func (c *replacePixelsCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error { - f, err := c.dst.createFramebufferIfNeeded(context) +func (c *replacePixelsCommand) Exec(indexOffsetInBytes int) error { + f, err := c.dst.createFramebufferIfNeeded() if err != nil { return err } - if err := f.setAsViewport(context); err != nil { + if err := f.setAsViewport(); err != nil { return err } // Filling with non black or white color is required here for glTexSubImage2D. // Very mysterious but this actually works (Issue #186). // This is needed even after fixing a shader bug at f537378f2a6a8ef56e1acf1c03034967b77c7b51. - if err := context.FillFramebuffer(0, 0, 0.5, 1); err != nil { + if err := opengl.GetContext().FillFramebuffer(0, 0, 0.5, 1); err != nil { return err } // This is necessary on Android. We can't call glClear just before glTexSubImage2D without // glFlush. glTexSubImage2D didn't work without this hack at least on Nexus 5x (#211). // This also happens when a fillCommand precedes a replacePixelsCommand. // TODO: Can we have a better way like optimizing commands? - context.Flush() - if err := context.BindTexture(c.dst.texture.native); err != nil { + opengl.GetContext().Flush() + if err := opengl.GetContext().BindTexture(c.dst.texture.native); err != nil { return err } - context.TexSubImage2D(c.pixels, NextPowerOf2Int(c.dst.width), NextPowerOf2Int(c.dst.height)) + opengl.GetContext().TexSubImage2D(c.pixels, NextPowerOf2Int(c.dst.width), NextPowerOf2Int(c.dst.height)) return nil } @@ -293,12 +292,12 @@ type disposeCommand struct { target *Image } -func (c *disposeCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error { +func (c *disposeCommand) Exec(indexOffsetInBytes int) error { if c.target.framebuffer != nil { - context.DeleteFramebuffer(c.target.framebuffer.native) + opengl.GetContext().DeleteFramebuffer(c.target.framebuffer.native) } if c.target.texture != nil { - context.DeleteTexture(c.target.texture.native) + opengl.GetContext().DeleteTexture(c.target.texture.native) } return nil } @@ -309,7 +308,7 @@ type newImageFromImageCommand struct { filter opengl.Filter } -func (c *newImageFromImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error { +func (c *newImageFromImageCommand) Exec(indexOffsetInBytes int) error { origSize := c.img.Bounds().Size() if origSize.X < 1 { return errors.New("graphics: width must be equal or more than 1.") @@ -321,7 +320,7 @@ func (c *newImageFromImageCommand) Exec(context *opengl.Context, indexOffsetInBy if c.img.Bounds() != image.Rect(0, 0, NextPowerOf2Int(w), NextPowerOf2Int(h)) { panic(fmt.Sprintf("graphics: invalid image bounds: %v", c.img.Bounds())) } - native, err := context.NewTexture(w, h, c.img.Pix, c.filter) + native, err := opengl.GetContext().NewTexture(w, h, c.img.Pix, c.filter) if err != nil { return err } @@ -338,7 +337,7 @@ type newImageCommand struct { filter opengl.Filter } -func (c *newImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error { +func (c *newImageCommand) Exec(indexOffsetInBytes int) error { w := NextPowerOf2Int(c.width) h := NextPowerOf2Int(c.height) if w < 1 { @@ -347,7 +346,7 @@ func (c *newImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) if h < 1 { return errors.New("graphics: height must be equal or more than 1.") } - native, err := context.NewTexture(w, h, nil, c.filter) + native, err := opengl.GetContext().NewTexture(w, h, nil, c.filter) if err != nil { return err } @@ -363,7 +362,7 @@ type newScreenFramebufferImageCommand struct { height int } -func (c *newScreenFramebufferImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error { +func (c *newScreenFramebufferImageCommand) Exec(indexOffsetInBytes int) error { if c.width < 1 { return errors.New("graphics: width must be equal or more than 1.") } @@ -371,7 +370,7 @@ func (c *newScreenFramebufferImageCommand) Exec(context *opengl.Context, indexOf return errors.New("graphics: height must be equal or more than 1.") } f := &framebuffer{ - native: context.ScreenFramebuffer(), + native: opengl.GetContext().ScreenFramebuffer(), flipY: true, } c.result.framebuffer = f diff --git a/internal/graphics/framebuffer.go b/internal/graphics/framebuffer.go index 9b966c5eb..e6ff22c45 100644 --- a/internal/graphics/framebuffer.go +++ b/internal/graphics/framebuffer.go @@ -38,8 +38,8 @@ type framebuffer struct { proMatrix []float32 } -func newFramebufferFromTexture(context *opengl.Context, texture *texture) (*framebuffer, error) { - native, err := context.NewFramebuffer(opengl.Texture(texture.native)) +func newFramebufferFromTexture(texture *texture) (*framebuffer, error) { + native, err := opengl.GetContext().NewFramebuffer(opengl.Texture(texture.native)) if err != nil { return nil, err } @@ -50,10 +50,10 @@ func newFramebufferFromTexture(context *opengl.Context, texture *texture) (*fram const viewportSize = 4096 -func (f *framebuffer) setAsViewport(context *opengl.Context) error { +func (f *framebuffer) setAsViewport() error { width := viewportSize height := viewportSize - return context.SetViewport(f.native, width, height) + return opengl.GetContext().SetViewport(f.native, width, height) } func (f *framebuffer) projectionMatrix(height int) []float32 { diff --git a/internal/graphics/image.go b/internal/graphics/image.go index cf3d71a57..de3266fbc 100644 --- a/internal/graphics/image.go +++ b/internal/graphics/image.go @@ -145,16 +145,16 @@ func (i *Image) DrawImage(src *Image, vertices []float32, clr *affine.ColorM, mo theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, clr, mode) } -func (i *Image) Pixels(context *opengl.Context) ([]uint8, error) { +func (i *Image) Pixels() ([]uint8, error) { // Flush the enqueued commands so that pixels are certainly read. - if err := theCommandQueue.Flush(context); err != nil { + if err := theCommandQueue.Flush(); err != nil { return nil, err } - f, err := i.createFramebufferIfNeeded(context) + f, err := i.createFramebufferIfNeeded() if err != nil { return nil, err } - return context.FramebufferPixels(f.native, NextPowerOf2Int(i.width), NextPowerOf2Int(i.height)) + return opengl.GetContext().FramebufferPixels(f.native, NextPowerOf2Int(i.width), NextPowerOf2Int(i.height)) } func (i *Image) ReplacePixels(p []uint8) { @@ -167,15 +167,15 @@ func (i *Image) ReplacePixels(p []uint8) { theCommandQueue.Enqueue(c) } -func (i *Image) IsInvalidated(context *opengl.Context) bool { - return !context.IsTexture(i.texture.native) +func (i *Image) IsInvalidated() bool { + return !opengl.GetContext().IsTexture(i.texture.native) } -func (i *Image) createFramebufferIfNeeded(context *opengl.Context) (*framebuffer, error) { +func (i *Image) createFramebufferIfNeeded() (*framebuffer, error) { if i.framebuffer != nil { return i.framebuffer, nil } - f, err := newFramebufferFromTexture(context, i.texture) + f, err := newFramebufferFromTexture(i.texture) if err != nil { return nil, err } diff --git a/internal/graphics/program.go b/internal/graphics/program.go index 95085cd37..e801ae4ba 100644 --- a/internal/graphics/program.go +++ b/internal/graphics/program.go @@ -46,26 +46,26 @@ func (a *arrayBufferLayout) totalBytes() int { return a.total } -func (a *arrayBufferLayout) newArrayBuffer(c *opengl.Context) opengl.Buffer { - return c.NewBuffer(opengl.ArrayBuffer, a.totalBytes()*4*maxQuads, opengl.DynamicDraw) +func (a *arrayBufferLayout) newArrayBuffer() opengl.Buffer { + return opengl.GetContext().NewBuffer(opengl.ArrayBuffer, a.totalBytes()*4*maxQuads, opengl.DynamicDraw) } -func (a *arrayBufferLayout) enable(c *opengl.Context, program opengl.Program) { +func (a *arrayBufferLayout) enable(program opengl.Program) { for _, p := range a.parts { - c.EnableVertexAttribArray(program, p.name) + opengl.GetContext().EnableVertexAttribArray(program, p.name) } total := a.totalBytes() offset := 0 for _, p := range a.parts { - c.VertexAttribPointer(program, p.name, p.num, p.dataType, p.normalize, total, offset) + opengl.GetContext().VertexAttribPointer(program, p.name, p.num, p.dataType, p.normalize, total, offset) offset += p.dataType.SizeInBytes() * p.num } } -func (a *arrayBufferLayout) disable(c *opengl.Context, program opengl.Program) { +func (a *arrayBufferLayout) disable(program opengl.Program) { // TODO: Disabling should be done in reversed order? for _, p := range a.parts { - c.DisableVertexAttribArray(program, p.name) + opengl.GetContext().DisableVertexAttribArray(program, p.name) } } @@ -125,12 +125,12 @@ const ( maxQuads = indicesNum / 6 ) -func Reset(context *opengl.Context) error { - return theOpenGLState.reset(context) +func Reset() error { + return theOpenGLState.reset() } -func (s *openGLState) reset(context *opengl.Context) error { - if err := context.Reset(); err != nil { +func (s *openGLState) reset() error { + if err := opengl.GetContext().Reset(); err != nil { return err } s.lastProgram = zeroProgram @@ -138,19 +138,19 @@ func (s *openGLState) reset(context *opengl.Context) error { s.lastColorMatrix = nil s.lastColorMatrixTranslation = nil - shaderVertexModelviewNative, err := context.NewShader(opengl.VertexShader, shader(context, shaderVertexModelview)) + shaderVertexModelviewNative, err := opengl.GetContext().NewShader(opengl.VertexShader, shader(shaderVertexModelview)) if err != nil { panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err)) } - defer context.DeleteShader(shaderVertexModelviewNative) + defer opengl.GetContext().DeleteShader(shaderVertexModelviewNative) - shaderFragmentTextureNative, err := context.NewShader(opengl.FragmentShader, shader(context, shaderFragmentTexture)) + shaderFragmentTextureNative, err := opengl.GetContext().NewShader(opengl.FragmentShader, shader(shaderFragmentTexture)) if err != nil { panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err)) } - defer context.DeleteShader(shaderFragmentTextureNative) + defer opengl.GetContext().DeleteShader(shaderFragmentTextureNative) - s.programTexture, err = context.NewProgram([]opengl.Shader{ + s.programTexture, err = opengl.GetContext().NewProgram([]opengl.Shader{ shaderVertexModelviewNative, shaderFragmentTextureNative, }) @@ -158,7 +158,7 @@ func (s *openGLState) reset(context *opengl.Context) error { return err } - s.arrayBuffer = theArrayBufferLayout.newArrayBuffer(context) + s.arrayBuffer = theArrayBufferLayout.newArrayBuffer() indices := make([]uint16, 6*maxQuads) for i := uint16(0); i < maxQuads; i++ { @@ -169,7 +169,7 @@ func (s *openGLState) reset(context *opengl.Context) error { indices[6*i+4] = 4*i + 2 indices[6*i+5] = 4*i + 3 } - s.indexBufferQuads = context.NewBuffer(opengl.ElementArrayBuffer, indices, opengl.StaticDraw) + s.indexBufferQuads = opengl.GetContext().NewBuffer(opengl.ElementArrayBuffer, indices, opengl.StaticDraw) return nil } @@ -189,20 +189,19 @@ func areSameFloat32Array(a, b []float32) bool { type programContext struct { state *openGLState program opengl.Program - context *opengl.Context projectionMatrix []float32 texture opengl.Texture colorM affine.ColorM } func (p *programContext) begin() error { - c := p.context + c := opengl.GetContext() if p.state.lastProgram != p.program { c.UseProgram(p.program) if p.state.lastProgram != zeroProgram { - theArrayBufferLayout.disable(c, p.state.lastProgram) + theArrayBufferLayout.disable(p.state.lastProgram) } - theArrayBufferLayout.enable(c, p.program) + theArrayBufferLayout.enable(p.program) p.state.lastProgram = p.state.programTexture p.state.lastProjectionMatrix = nil diff --git a/internal/graphics/shader.go b/internal/graphics/shader.go index 3c3d3d314..1dfdd7eb4 100644 --- a/internal/graphics/shader.go +++ b/internal/graphics/shader.go @@ -27,9 +27,9 @@ const ( shaderFragmentTexture ) -func shader(c *opengl.Context, id shaderId) string { +func shader(id shaderId) string { str := shaders[id] - if !c.GlslHighpSupported() { + if !opengl.GetContext().GlslHighpSupported() { str = strings.Replace(str, "highp ", "", -1) str = strings.Replace(str, "lowp ", "", -1) } diff --git a/internal/loop/run.go b/internal/loop/run.go index 651825d16..db4414ad9 100644 --- a/internal/loop/run.go +++ b/internal/loop/run.go @@ -18,7 +18,6 @@ import ( "errors" "time" - "github.com/hajimehoshi/ebiten/internal/opengl" "github.com/hajimehoshi/ebiten/internal/sync" "github.com/hajimehoshi/ebiten/internal/ui" ) @@ -76,7 +75,7 @@ func (c *runContext) updateFPS(fps float64) { type GraphicsContext interface { SetSize(width, height int, scale float64) error - UpdateAndDraw(context *opengl.Context, updateCount int) error + UpdateAndDraw(updateCount int) error Invalidate() } @@ -150,7 +149,7 @@ func (c *runContext) render(g GraphicsContext) error { if tt == 0 && (int64(time.Second)/int64(fps)-int64(5*time.Millisecond)) < t { tt = 1 } - if err := g.UpdateAndDraw(ui.GLContext(), tt); err != nil { + if err := g.UpdateAndDraw(tt); err != nil { return err } c.lastUpdated += int64(tt) * int64(time.Second) / int64(fps) diff --git a/internal/opengl/context.go b/internal/opengl/context.go index 36bfe0b1c..d69ecd159 100644 --- a/internal/opengl/context.go +++ b/internal/opengl/context.go @@ -47,6 +47,12 @@ type Context struct { context } +var theContext *Context + +func GetContext() *Context { + return theContext +} + func (c *Context) BindTexture(t Texture) error { if c.lastTexture == t { return nil diff --git a/internal/opengl/context_desktop.go b/internal/opengl/context_desktop.go index 8727c3856..597e44ebf 100644 --- a/internal/opengl/context_desktop.go +++ b/internal/opengl/context_desktop.go @@ -73,10 +73,10 @@ type context struct { runOnMainThread func(func() error) error } -func NewContext(runOnMainThread func(func() error) error) (*Context, error) { +func Init(runOnMainThread func(func() error) error) { c := &Context{} c.runOnMainThread = runOnMainThread - return c, nil + theContext = c } func (c *Context) runOnContextThread(f func() error) error { diff --git a/internal/opengl/context_js.go b/internal/opengl/context_js.go index f7d213791..07d8aaa4b 100644 --- a/internal/opengl/context_js.go +++ b/internal/opengl/context_js.go @@ -91,7 +91,7 @@ type context struct { lastProgramID programID } -func NewContext() (*Context, error) { +func Init() error { var gl *webgl.Context if js.Global.Get("require") == js.Undefined { @@ -103,7 +103,7 @@ func NewContext() (*Context, error) { PremultipliedAlpha: true, }) if err != nil { - return nil, err + return err } } else { // TODO: Now Ebiten with headless-gl doesn't work well (#141). @@ -126,7 +126,8 @@ func NewContext() (*Context, error) { c.loseContext.Call("loseContext") }) } - return c, nil + theContext = c + return nil } func (c *Context) Reset() error { diff --git a/internal/opengl/context_mobile.go b/internal/opengl/context_mobile.go index 432adf371..81e75c689 100644 --- a/internal/opengl/context_mobile.go +++ b/internal/opengl/context_mobile.go @@ -72,10 +72,10 @@ type context struct { worker mgl.Worker } -func NewContext() (*Context, error) { +func Init() { c := &Context{} c.gl, c.worker = mgl.NewContext() - return c, nil + theContext = c } func (c *Context) DoWork(chError <-chan error, chDone <-chan struct{}) error { diff --git a/internal/restorable/image.go b/internal/restorable/image.go index 36de52a13..87ca88b81 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -167,14 +167,14 @@ func (p *Image) appendDrawImageHistory(image *Image, vertices []float32, colorm // At returns a color value at (x, y). // // Note that this must not be called until context is available. -func (p *Image) At(x, y int, context *opengl.Context) (color.RGBA, error) { +func (p *Image) At(x, y int) (color.RGBA, error) { w, h := p.image.Size() w2, h2 := graphics.NextPowerOf2Int(w), graphics.NextPowerOf2Int(h) if x < 0 || y < 0 || w2 <= x || h2 <= y { return color.RGBA{}, nil } if p.basePixels == nil || p.drawImageHistory != nil || p.stale { - if err := p.readPixelsFromGPU(p.image, context); err != nil { + if err := p.readPixelsFromGPU(p.image); err != nil { return color.RGBA{}, err } } @@ -195,9 +195,9 @@ func (p *Image) makeStaleIfDependingOn(target *Image) { } } -func (p *Image) readPixelsFromGPU(image *graphics.Image, context *opengl.Context) error { +func (p *Image) readPixelsFromGPU(image *graphics.Image) error { var err error - p.basePixels, err = image.Pixels(context) + p.basePixels, err = image.Pixels() if err != nil { return err } @@ -207,14 +207,14 @@ func (p *Image) readPixelsFromGPU(image *graphics.Image, context *opengl.Context return nil } -func (p *Image) resolveStalePixels(context *opengl.Context) error { +func (p *Image) resolveStalePixels() error { if p.volatile { return nil } if !p.stale { return nil } - return p.readPixelsFromGPU(p.image, context) + return p.readPixelsFromGPU(p.image) } func (p *Image) hasDependency() bool { @@ -225,7 +225,7 @@ func (p *Image) hasDependency() bool { } // Restore restores *graphics.Image from the pixels using its state. -func (p *Image) restore(context *opengl.Context) error { +func (p *Image) restore() error { w, h := p.image.Size() if p.screen { // The screen image should also be recreated because framebuffer might @@ -273,7 +273,7 @@ func (p *Image) restore(context *opengl.Context) error { p.image = gimg var err error - p.basePixels, err = gimg.Pixels(context) + p.basePixels, err = gimg.Pixels() if err != nil { return err } @@ -295,6 +295,6 @@ func (p *Image) Dispose() { runtime.SetFinalizer(p, nil) } -func (p *Image) IsInvalidated(context *opengl.Context) bool { - return p.image.IsInvalidated(context) +func (p *Image) IsInvalidated() bool { + return p.image.IsInvalidated() } diff --git a/internal/restorable/images.go b/internal/restorable/images.go index 4d742a815..5ecc05a1d 100644 --- a/internal/restorable/images.go +++ b/internal/restorable/images.go @@ -15,7 +15,6 @@ package restorable import ( - "github.com/hajimehoshi/ebiten/internal/opengl" "github.com/hajimehoshi/ebiten/internal/sync" ) @@ -29,12 +28,12 @@ var theImages = &images{ images: map[*Image]struct{}{}, } -func ResolveStalePixels(context *opengl.Context) error { - return theImages.resolveStalePixels(context) +func ResolveStalePixels() error { + return theImages.resolveStalePixels() } -func Restore(context *opengl.Context) error { - return theImages.restore(context) +func Restore() error { + return theImages.restore() } func ClearVolatileImages() { @@ -53,12 +52,12 @@ func (i *images) remove(img *Image) { delete(i.images, img) } -func (i *images) resolveStalePixels(context *opengl.Context) error { +func (i *images) resolveStalePixels() error { i.m.Lock() defer i.m.Unlock() i.lastChecked = nil for img := range i.images { - if err := img.resolveStalePixels(context); err != nil { + if err := img.resolveStalePixels(); err != nil { return err } } @@ -86,7 +85,7 @@ func (i *images) resetPixelsIfDependingOn(target *Image) { i.m.Unlock() } -func (i *images) restore(context *opengl.Context) error { +func (i *images) restore() error { i.m.Lock() defer i.m.Unlock() // Framebuffers/textures cannot be disposed since framebuffers/textures that @@ -102,12 +101,12 @@ func (i *images) restore(context *opengl.Context) error { } // Images depending on other images should be processed first. for _, img := range imagesWithoutDependency { - if err := img.restore(context); err != nil { + if err := img.restore(); err != nil { return err } } for _, img := range imagesWithDependency { - if err := img.restore(context); err != nil { + if err := img.restore(); err != nil { return err } } diff --git a/internal/ui/glcontext.go b/internal/ui/glcontext.go deleted file mode 100644 index 8ff8d5290..000000000 --- a/internal/ui/glcontext.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2016 The Ebiten Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ui - -import ( - "github.com/hajimehoshi/ebiten/internal/opengl" -) - -var glContext *opengl.Context - -func GLContext() *opengl.Context { - return glContext -} diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index 58beb7733..1c22ab847 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -178,11 +178,7 @@ func Run(width, height int, scale float64, title string, g GraphicsContext) erro u := currentUI // GLContext must be created before setting the screen size, which requires // swapping buffers. - var err error - glContext, err = opengl.NewContext(currentUI.runOnMainThread) - if err != nil { - return err - } + opengl.Init(currentUI.runOnMainThread) if err := u.runOnMainThread(func() error { m := glfw.GetPrimaryMonitor() v := m.GetVideoMode() @@ -275,7 +271,7 @@ func (u *userInterface) loop(g GraphicsContext) error { return err } // The bound framebuffer must be the default one (0) before swapping buffers. - if err := glContext.BindScreenFramebuffer(); err != nil { + if err := opengl.GetContext().BindScreenFramebuffer(); err != nil { return err } _ = u.runOnMainThread(func() error { diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index cfd7d9851..bb849e663 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -72,8 +72,8 @@ func (u *userInterface) update(g GraphicsContext) error { if !u.windowFocus { return nil } - if glContext.IsContextLost() { - glContext.RestoreContext() + if opengl.GetContext().IsContextLost() { + opengl.GetContext().RestoreContext() g.Invalidate() } currentInput.updateGamepads() @@ -280,9 +280,7 @@ func Run(width, height int, scale float64, title string, g GraphicsContext) erro doc.Set("title", title) u.setScreenSize(width, height, scale) canvas.Call("focus") - var err error - glContext, err = opengl.NewContext() - if err != nil { + if err := opengl.Init(); err != nil { return err } return u.loop(g) diff --git a/internal/ui/ui_mobile.go b/internal/ui/ui_mobile.go index ab28bdc63..5c56e7ce8 100644 --- a/internal/ui/ui_mobile.go +++ b/internal/ui/ui_mobile.go @@ -38,7 +38,7 @@ func Render(chError <-chan error) error { // TODO: Check this is called on the rendering thread select { case chRender <- struct{}{}: - return glContext.DoWork(chError, chRenderEnd) + return opengl.GetContext().DoWork(chError, chRenderEnd) case <-time.After(500 * time.Millisecond): // This function must not be blocked. We need to break for timeout. return nil @@ -66,11 +66,7 @@ func Run(width, height int, scale float64, title string, g GraphicsContext) erro u.height = height u.scale = scale // title is ignored? - var err error - glContext, err = opengl.NewContext() - if err != nil { - return err - } + opengl.Init() for { if err := u.update(g); err != nil { return err