diff --git a/internal/atlas/image.go b/internal/atlas/image.go index bd313b7fd..45349df76 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -752,7 +752,7 @@ func EndFrame() error { return nil } -func SwapBuffers(graphicsDriver graphicsdriver.Graphics, swapBuffersForGL func()) error { +func SwapBuffers(graphicsDriver graphicsdriver.Graphics) error { func() { backendsM.Lock() defer backendsM.Unlock() @@ -762,7 +762,7 @@ func SwapBuffers(graphicsDriver graphicsdriver.Graphics, swapBuffersForGL func() } }() - if err := restorable.SwapBuffers(graphicsDriver, swapBuffersForGL); err != nil { + if err := restorable.SwapBuffers(graphicsDriver); err != nil { return err } return nil diff --git a/internal/graphicscommand/commandqueue.go b/internal/graphicscommand/commandqueue.go index cf0c55275..49fc9e776 100644 --- a/internal/graphicscommand/commandqueue.go +++ b/internal/graphicscommand/commandqueue.go @@ -59,8 +59,8 @@ func SetVsyncEnabled(enabled bool, graphicsDriver graphicsdriver.Graphics) { // FlushCommands flushes the command queue and present the screen if needed. // If endFrame is true, the current screen might be used to present. -func FlushCommands(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error { - if err := theCommandQueueManager.flush(graphicsDriver, endFrame, swapBuffersForGL); err != nil { +func FlushCommands(graphicsDriver graphicsdriver.Graphics, endFrame bool) error { + if err := theCommandQueueManager.flush(graphicsDriver, endFrame); err != nil { return err } return nil @@ -178,7 +178,7 @@ func (q *commandQueue) Enqueue(command command) { } // Flush flushes the command queue. -func (q *commandQueue) Flush(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error { +func (q *commandQueue) Flush(graphicsDriver graphicsdriver.Graphics, endFrame bool) error { if err := q.err.Load(); err != nil { return err.(error) } @@ -212,10 +212,6 @@ func (q *commandQueue) Flush(graphicsDriver graphicsdriver.Graphics, endFrame bo return } - if endFrame && swapBuffersForGL != nil { - swapBuffersForGL() - } - theCommandQueueManager.putCommandQueue(q) }, sync) @@ -504,7 +500,7 @@ func (c *commandQueueManager) enqueueDrawTrianglesCommand(dst *Image, srcs [grap c.current.EnqueueDrawTrianglesCommand(dst, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule) } -func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error { +func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool) error { // Switch the command queue. prev := c.current q, err := c.pool.get() @@ -516,7 +512,7 @@ func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endF if prev == nil { return nil } - if err := prev.Flush(graphicsDriver, endFrame, swapBuffersForGL); err != nil { + if err := prev.Flush(graphicsDriver, endFrame); err != nil { return err } return nil diff --git a/internal/graphicscommand/image.go b/internal/graphicscommand/image.go index 40abd3156..562712e7e 100644 --- a/internal/graphicscommand/image.go +++ b/internal/graphicscommand/image.go @@ -154,7 +154,7 @@ func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, args []graphi args: args, } theCommandQueueManager.enqueueCommand(c) - if err := theCommandQueueManager.flush(graphicsDriver, false, nil); err != nil { + if err := theCommandQueueManager.flush(graphicsDriver, false); err != nil { return err } return nil @@ -183,7 +183,7 @@ func (i *Image) IsInvalidated(graphicsDriver graphicsdriver.Graphics) (bool, err image: i, } theCommandQueueManager.enqueueCommand(c) - if err := theCommandQueueManager.flush(graphicsDriver, false, nil); err != nil { + if err := theCommandQueueManager.flush(graphicsDriver, false); err != nil { return false, err } return c.result, nil diff --git a/internal/graphicsdriver/opengl/egl_nintendosdk.go b/internal/graphicsdriver/opengl/egl_nintendosdk.go index fbf3751d0..c1ee30281 100644 --- a/internal/graphicsdriver/opengl/egl_nintendosdk.go +++ b/internal/graphicsdriver/opengl/egl_nintendosdk.go @@ -33,15 +33,16 @@ type egl struct { context C.EGLContext } -func (e *egl) init(nativeWindowHandle uintptr) error { - // Initialize EGL +func newEGL(nativeWindowHandle uintptr) (*egl, error) { + e := &egl{} + e.display = C.eglGetDisplay(C.NativeDisplayType(C.EGL_DEFAULT_DISPLAY)) if e.display == 0 { - return fmt.Errorf("opengl: eglGetDisplay failed") + return nil, fmt.Errorf("opengl: eglGetDisplay failed") } if r := C.eglInitialize(e.display, nil, nil); r == 0 { - return fmt.Errorf("opengl: eglInitialize failed") + return nil, fmt.Errorf("opengl: eglInitialize failed") } configAttribs := []C.EGLint{ @@ -55,20 +56,20 @@ func (e *egl) init(nativeWindowHandle uintptr) error { var numConfigs C.EGLint var config C.EGLConfig if r := C.eglChooseConfig(e.display, &configAttribs[0], &config, 1, &numConfigs); r == 0 { - return fmt.Errorf("opengl: eglChooseConfig failed") + return nil, fmt.Errorf("opengl: eglChooseConfig failed") } if numConfigs != 1 { - return fmt.Errorf("opengl: eglChooseConfig failed: numConfigs must be 1 but %d", numConfigs) + return nil, fmt.Errorf("opengl: eglChooseConfig failed: numConfigs must be 1 but %d", numConfigs) } e.surface = C.eglCreateWindowSurface(e.display, config, C.NativeWindowType(nativeWindowHandle), nil) if e.surface == C.EGLSurface(C.EGL_NO_SURFACE) { - return fmt.Errorf("opengl: eglCreateWindowSurface failed") + return nil, fmt.Errorf("opengl: eglCreateWindowSurface failed") } // Set the current rendering API. if r := C.eglBindAPI(C.EGL_OPENGL_API); r == 0 { - return fmt.Errorf("opengl: eglBindAPI failed") + return nil, fmt.Errorf("opengl: eglBindAPI failed") } // Create new context and set it as current. @@ -81,10 +82,10 @@ func (e *egl) init(nativeWindowHandle uintptr) error { C.EGL_NONE} e.context = C.eglCreateContext(e.display, config, C.EGLContext(C.EGL_NO_CONTEXT), &contextAttribs[0]) if e.context == C.EGLContext(C.EGL_NO_CONTEXT) { - return fmt.Errorf("opengl: eglCreateContext failed: error: %d", C.eglGetError()) + return nil, fmt.Errorf("opengl: eglCreateContext failed: error: %d", C.eglGetError()) } - return nil + return e, nil } func (e *egl) makeContextCurrent() error { diff --git a/internal/graphicsdriver/opengl/graphics.go b/internal/graphicsdriver/opengl/graphics.go index b6f36d707..14a9fa1e7 100644 --- a/internal/graphicsdriver/opengl/graphics.go +++ b/internal/graphicsdriver/opengl/graphics.go @@ -54,6 +54,8 @@ type Graphics struct { // activatedTextures is a set of activated textures. // textureNative cannot be a map key unfortunately. activatedTextures []activatedTexture + + graphicsPlatform } func newGraphics(ctx gl.Context) *Graphics { diff --git a/internal/graphicsdriver/opengl/graphics_glfw.go b/internal/graphicsdriver/opengl/graphics_glfw.go index b5da83bee..3456ad574 100644 --- a/internal/graphicsdriver/opengl/graphics_glfw.go +++ b/internal/graphicsdriver/opengl/graphics_glfw.go @@ -26,6 +26,10 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk" ) +type graphicsPlatform struct { + window *glfw.Window +} + // NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL. // The returned graphics value is nil iff the error is not nil. func NewGraphics() (graphicsdriver.Graphics, error) { @@ -83,9 +87,12 @@ func setGLFWClientAPI(isES bool) error { return nil } +func (g *Graphics) SetGLFWWindow(window *glfw.Window) { + g.window = window +} + func (g *Graphics) makeContextCurrent() error { - // TODO: Implement this (#2714). - return nil + return g.window.MakeContextCurrent() } func (g *Graphics) swapBuffers() error { @@ -105,6 +112,8 @@ func (g *Graphics) swapBuffers() error { } } - // TODO: Implement this (#2714). + if err := g.window.SwapBuffers(); err != nil { + return err + } return nil } diff --git a/internal/graphicsdriver/opengl/graphics_js.go b/internal/graphicsdriver/opengl/graphics_js.go index 42f444dee..1d98d6119 100644 --- a/internal/graphicsdriver/opengl/graphics_js.go +++ b/internal/graphicsdriver/opengl/graphics_js.go @@ -22,6 +22,9 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl" ) +type graphicsPlatform struct { +} + // NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL. // The returned graphics value is nil iff the error is not nil. func NewGraphics(canvas js.Value) (graphicsdriver.Graphics, error) { diff --git a/internal/graphicsdriver/opengl/graphics_mobile.go b/internal/graphicsdriver/opengl/graphics_mobile.go index 900712a3e..3f2481ab5 100644 --- a/internal/graphicsdriver/opengl/graphics_mobile.go +++ b/internal/graphicsdriver/opengl/graphics_mobile.go @@ -23,6 +23,9 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl" ) +type graphicsPlatform struct { +} + // NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL. // The returned graphics value is nil iff the error is not nil. func NewGraphics(context mgl.Context) (graphicsdriver.Graphics, error) { diff --git a/internal/graphicsdriver/opengl/graphics_nintendosdk.go b/internal/graphicsdriver/opengl/graphics_nintendosdk.go index 4ff4ec6fa..9343d64bf 100644 --- a/internal/graphicsdriver/opengl/graphics_nintendosdk.go +++ b/internal/graphicsdriver/opengl/graphics_nintendosdk.go @@ -21,25 +21,29 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl" ) -var ( - theEGL egl -) +type graphicsPlatform struct { + egl *egl +} func NewGraphics(nativeWindowType uintptr) (graphicsdriver.Graphics, error) { - theEGL.init(nativeWindowType) - ctx, err := gl.NewDefaultContext() if err != nil { return nil, err } - return newGraphics(ctx), nil + g := newGraphics(ctx) + e, err := newEGL(nativeWindowType) + if err != nil { + return nil, err + } + g.egl = e + return g, nil } func (g *Graphics) makeContextCurrent() error { - return theEGL.makeContextCurrent() + return g.egl.makeContextCurrent() } func (g *Graphics) swapBuffers() error { - theEGL.swapBuffers() + g.egl.swapBuffers() return nil } diff --git a/internal/restorable/export_test.go b/internal/restorable/export_test.go index 1be76b611..10071b879 100644 --- a/internal/restorable/export_test.go +++ b/internal/restorable/export_test.go @@ -21,7 +21,7 @@ import ( ) func ResolveStaleImages(graphicsDriver graphicsdriver.Graphics) error { - return resolveStaleImages(graphicsDriver, false, nil) + return resolveStaleImages(graphicsDriver, false) } func AppendRegionRemovingDuplicates(regions *[]image.Rectangle, region image.Rectangle) { diff --git a/internal/restorable/images.go b/internal/restorable/images.go index 60e1d32ba..f65cf0fdd 100644 --- a/internal/restorable/images.go +++ b/internal/restorable/images.go @@ -56,7 +56,7 @@ var theImages = &images{ shaders: map[*Shader]struct{}{}, } -func SwapBuffers(graphicsDriver graphicsdriver.Graphics, swapBuffersForGL func()) error { +func SwapBuffers(graphicsDriver graphicsdriver.Graphics) error { if debug.IsDebug { debug.Logf("Internal image sizes:\n") imgs := make([]*graphicscommand.Image, 0, len(theImages.images)) @@ -65,13 +65,13 @@ func SwapBuffers(graphicsDriver graphicsdriver.Graphics, swapBuffersForGL func() } graphicscommand.LogImagesInfo(imgs) } - return resolveStaleImages(graphicsDriver, true, swapBuffersForGL) + return resolveStaleImages(graphicsDriver, true) } // resolveStaleImages flushes the queued draw commands and resolves all stale images. // If endFrame is true, the current screen might be used to present when flushing the commands. -func resolveStaleImages(graphicsDriver graphicsdriver.Graphics, endFrame bool, swapBuffersForGL func()) error { - if err := graphicscommand.FlushCommands(graphicsDriver, endFrame, swapBuffersForGL); err != nil { +func resolveStaleImages(graphicsDriver graphicsdriver.Graphics, endFrame bool) error { + if err := graphicscommand.FlushCommands(graphicsDriver, endFrame); err != nil { return err } if !needsRestoring() { diff --git a/internal/ui/context.go b/internal/ui/context.go index ff957b020..c4cd4a131 100644 --- a/internal/ui/context.go +++ b/internal/ui/context.go @@ -63,12 +63,12 @@ func newContext(game Game) *context { } } -func (c *context) updateFrame(graphicsDriver graphicsdriver.Graphics, outsideWidth, outsideHeight float64, deviceScaleFactor float64, ui *UserInterface, swapBuffersForGL func()) error { +func (c *context) updateFrame(graphicsDriver graphicsdriver.Graphics, outsideWidth, outsideHeight float64, deviceScaleFactor float64, ui *UserInterface) error { // TODO: If updateCount is 0 and vsync is disabled, swapping buffers can be skipped. - return c.updateFrameImpl(graphicsDriver, clock.UpdateFrame(), outsideWidth, outsideHeight, deviceScaleFactor, ui, false, swapBuffersForGL) + return c.updateFrameImpl(graphicsDriver, clock.UpdateFrame(), outsideWidth, outsideHeight, deviceScaleFactor, ui, false) } -func (c *context) forceUpdateFrame(graphicsDriver graphicsdriver.Graphics, outsideWidth, outsideHeight float64, deviceScaleFactor float64, ui *UserInterface, swapBuffersForGL func()) error { +func (c *context) forceUpdateFrame(graphicsDriver graphicsdriver.Graphics, outsideWidth, outsideHeight float64, deviceScaleFactor float64, ui *UserInterface) error { n := 1 if ui.GraphicsLibrary() == GraphicsLibraryDirectX { // On DirectX, both framebuffers in the swap chain should be updated. @@ -76,14 +76,14 @@ func (c *context) forceUpdateFrame(graphicsDriver graphicsdriver.Graphics, outsi n = 2 } for i := 0; i < n; i++ { - if err := c.updateFrameImpl(graphicsDriver, 1, outsideWidth, outsideHeight, deviceScaleFactor, ui, true, swapBuffersForGL); err != nil { + if err := c.updateFrameImpl(graphicsDriver, 1, outsideWidth, outsideHeight, deviceScaleFactor, ui, true); err != nil { return err } } return nil } -func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, updateCount int, outsideWidth, outsideHeight float64, deviceScaleFactor float64, ui *UserInterface, forceDraw bool, swapBuffersForGL func()) (err error) { +func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, updateCount int, outsideWidth, outsideHeight float64, deviceScaleFactor float64, ui *UserInterface, forceDraw bool) (err error) { // The given outside size can be 0 e.g. just after restoring from the fullscreen mode on Windows (#1589) // Just ignore such cases. Otherwise, creating a zero-sized framebuffer causes a panic. if outsideWidth == 0 || outsideHeight == 0 { @@ -102,7 +102,7 @@ func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, update return } - if err1 := atlas.SwapBuffers(graphicsDriver, swapBuffersForGL); err1 != nil && err == nil { + if err1 := atlas.SwapBuffers(graphicsDriver); err1 != nil && err == nil { err = err1 return } diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index 7f4fc09e4..aa0e189eb 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -1177,7 +1177,10 @@ func (u *UserInterface) initOnMainThread(options *RunOptions) error { } } - if g, ok := u.graphicsDriver.(interface{ SetWindow(uintptr) }); ok { + switch g := u.graphicsDriver.(type) { + case interface{ SetGLFWWindow(window *glfw.Window) }: + g.SetGLFWWindow(u.window) + case interface{ SetWindow(uintptr) }: w, err := u.nativeWindow() if err != nil { return err @@ -1405,15 +1408,6 @@ func (u *UserInterface) loopGame() (ferr error) { }) }() - u.renderThread.Call(func() { - if u.GraphicsLibrary() == GraphicsLibraryOpenGL { - if err := u.window.MakeContextCurrent(); err != nil { - u.setError(err) - return - } - } - }) - for { if err := u.updateGame(); err != nil { return err @@ -1458,13 +1452,7 @@ func (u *UserInterface) updateGame() error { return err } - if err := u.context.updateFrame(u.graphicsDriver, outsideWidth, outsideHeight, deviceScaleFactor, u, func() { - // This works only for OpenGL. - if err := u.swapBuffersOnRenderThread(); err != nil { - u.setError(err) - return - } - }); err != nil { + if err := u.context.updateFrame(u.graphicsDriver, outsideWidth, outsideHeight, deviceScaleFactor, u); err != nil { return err } @@ -1543,15 +1531,6 @@ func (u *UserInterface) updateIconIfNeeded() error { return nil } -func (u *UserInterface) swapBuffersOnRenderThread() error { - if u.GraphicsLibrary() == GraphicsLibraryOpenGL { - if err := u.window.SwapBuffers(); err != nil { - return err - } - } - return nil -} - // updateWindowSizeLimits must be called from the main thread. func (u *UserInterface) updateWindowSizeLimits() error { m, err := u.currentMonitor() diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index ceb5dd5d6..5e894e398 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -365,11 +365,11 @@ func (u *UserInterface) updateImpl(force bool) error { w, h := u.outsideSize() if force { - if err := u.context.forceUpdateFrame(u.graphicsDriver, w, h, u.DeviceScaleFactor(), u, nil); err != nil { + if err := u.context.forceUpdateFrame(u.graphicsDriver, w, h, u.DeviceScaleFactor(), u); err != nil { return err } } else { - if err := u.context.updateFrame(u.graphicsDriver, w, h, u.DeviceScaleFactor(), u, nil); err != nil { + if err := u.context.updateFrame(u.graphicsDriver, w, h, u.DeviceScaleFactor(), u); err != nil { return err } } diff --git a/internal/ui/ui_mobile.go b/internal/ui/ui_mobile.go index 9086838f2..271c4f6a7 100644 --- a/internal/ui/ui_mobile.go +++ b/internal/ui/ui_mobile.go @@ -330,7 +330,7 @@ func (u *UserInterface) update() error { }() w, h := u.outsideSize() - if err := u.context.updateFrame(u.graphicsDriver, w, h, u.DeviceScaleFactor(), u, nil); err != nil { + if err := u.context.updateFrame(u.graphicsDriver, w, h, u.DeviceScaleFactor(), u); err != nil { return err } return nil diff --git a/internal/ui/ui_nintendosdk.go b/internal/ui/ui_nintendosdk.go index a6f922bce..cb8ff1d47 100644 --- a/internal/ui/ui_nintendosdk.go +++ b/internal/ui/ui_nintendosdk.go @@ -95,7 +95,7 @@ func (u *UserInterface) loopGame() error { for { recordProfilerHeartbeat() - if err := u.context.updateFrame(u.graphicsDriver, float64(C.kScreenWidth), float64(C.kScreenHeight), deviceScaleFactor, u, nil); err != nil { + if err := u.context.updateFrame(u.graphicsDriver, float64(C.kScreenWidth), float64(C.kScreenHeight), deviceScaleFactor, u); err != nil { return err } } diff --git a/internal/ui/ui_playstation5.go b/internal/ui/ui_playstation5.go index b6e5af155..0a95e50d9 100644 --- a/internal/ui/ui_playstation5.go +++ b/internal/ui/ui_playstation5.go @@ -82,7 +82,7 @@ func (u *UserInterface) initOnMainThread(options *RunOptions) error { func (u *UserInterface) loopGame() error { for { - if err := u.context.updateFrame(u.graphicsDriver, screenWidth, screenHeight, deviceScaleFactor, u, nil); err != nil { + if err := u.context.updateFrame(u.graphicsDriver, screenWidth, screenHeight, deviceScaleFactor, u); err != nil { return err } }