diff --git a/app/egl.go b/app/egl.go index 46c306d8..3c5f2cd6 100644 --- a/app/egl.go +++ b/app/egl.go @@ -15,16 +15,21 @@ import ( type context struct { c *gl.Functions - driver *window + driver eglDriver eglCtx *eglContext - nwindow _EGLNativeWindowType - eglWin *eglWindow + eglWin _EGLNativeWindowType eglSurf _EGLSurface width, height int // For sRGB emulation. srgbFBO *gl.SRGBFBO } +type eglDriver interface { + eglDisplay() _EGLNativeDisplayType + eglWindow(visID int) (_EGLNativeWindowType, int, int, error) + eglDestroy() +} + type eglContext struct { disp _EGLDisplay config _EGLConfig @@ -62,27 +67,28 @@ const ( func (c *context) Release() { if c.srgbFBO != nil { c.srgbFBO.Release() + c.srgbFBO = nil } if c.eglSurf != nilEGLSurface { eglMakeCurrent(c.eglCtx.disp, nilEGLSurface, nilEGLSurface, nilEGLContext) eglDestroySurface(c.eglCtx.disp, c.eglSurf) c.eglSurf = nilEGLSurface } - if c.eglWin != nil { - c.eglWin.destroy() - c.eglWin = nil - } + c.eglWin = nilEGLNativeWindowType if c.eglCtx != nil { eglDestroyContext(c.eglCtx.disp, c.eglCtx.ctx) eglTerminate(c.eglCtx.disp) eglReleaseThread() c.eglCtx = nil } - c.driver = nil + if c.driver != nil { + c.driver.eglDestroy() + c.driver = nil + } } func (c *context) Present() error { - if c.eglWin == nil { + if c.eglWin == nilEGLNativeWindowType { panic("context is not active") } if c.srgbFBO != nil { @@ -97,13 +103,13 @@ func (c *context) Present() error { return nil } -func newContext(w *window) (*context, error) { - eglCtx, err := createContext(_EGLNativeDisplayType(w.display())) +func newContext(d eglDriver) (*context, error) { + eglCtx, err := createContext(d.eglDisplay()) if err != nil { return nil, err } c := &context{ - driver: w, + driver: d, eglCtx: eglCtx, c: new(gl.Functions), } @@ -119,9 +125,11 @@ func (c *context) Lock() {} func (c *context) Unlock() {} func (c *context) MakeCurrent() error { - w, width, height := c.driver.nativeWindow(int(c.eglCtx.visualID)) - win := _EGLNativeWindowType(w) - if c.nwindow == win && width == c.width && height == c.height { + win, width, height, err := c.driver.eglWindow(int(c.eglCtx.visualID)) + if err != nil { + return err + } + if c.eglWin == win && width == c.width && height == c.height { return nil } if win == nilEGLNativeWindowType { @@ -138,29 +146,14 @@ func (c *context) MakeCurrent() error { c.eglSurf = nilEGLSurface } c.width, c.height = width, height - c.nwindow = win - if c.nwindow == nilEGLNativeWindowType { - if c.eglWin != nil { - c.eglWin.destroy() - c.eglWin = nil - } + c.eglWin = win + if c.eglWin == nilEGLNativeWindowType { return nil } - if c.eglWin == nil { - var err error - c.eglWin, err = newEGLWindow(win, width, height) - if err != nil { - return err - } - } else { - c.eglWin.resize(width, height) - } - eglSurf, err := createSurfaceAndMakeCurrent(c.eglCtx, c.eglWin.window()) + eglSurf, err := createSurfaceAndMakeCurrent(c.eglCtx, win) c.eglSurf = eglSurf if err != nil { - c.eglWin.destroy() - c.eglWin = nil - c.nwindow = nilEGLNativeWindowType + c.eglWin = nilEGLNativeWindowType return err } if c.eglCtx.srgb { diff --git a/app/egl_android.go b/app/egl_android.go index 57b60dd5..9986e018 100644 --- a/app/egl_android.go +++ b/app/egl_android.go @@ -20,3 +20,15 @@ func eglCreateWindowSurface(disp _EGLDisplay, conf _EGLConfig, win _EGLNativeWin eglSurf := C.eglCreateWindowSurface(disp, conf, win, &attribs[0]) return eglSurf } + +func (w *window) eglDestroy() { +} + +func (w *window) eglDisplay() _EGLNativeDisplayType { + return nil +} + +func (w *window) eglWindow(visID int) (_EGLNativeWindowType, int, int, error) { + win, width, height := w.nativeWindow(visID) + return _EGLNativeWindowType(win), width, height, nil +} diff --git a/app/egl_wayland.go b/app/egl_wayland.go index d8fc4a5c..15a439eb 100644 --- a/app/egl_wayland.go +++ b/app/egl_wayland.go @@ -6,7 +6,7 @@ package app import ( "errors" - "unsafe" + "sync" ) /* @@ -24,29 +24,48 @@ type ( _EGLNativeWindowType = C.EGLNativeWindowType ) -type eglWindow struct { - w *C.struct_wl_egl_window +var eglWindows struct { + mu sync.Mutex + windows map[*C.struct_wl_surface]*C.struct_wl_egl_window } -func newEGLWindow(w _EGLNativeWindowType, width, height int) (*eglWindow, error) { - surf := (*C.struct_wl_surface)(unsafe.Pointer(w)) - win := C.wl_egl_window_create(surf, C.int(width), C.int(height)) - if win == nil { - return nil, errors.New("wl_egl_create_window failed") +func (w *window) eglDestroy() { + surf, _, _ := w.surface() + if surf == nil { + return + } + eglWindows.mu.Lock() + defer eglWindows.mu.Unlock() + if eglWin, ok := eglWindows.windows[surf]; ok { + C.wl_egl_window_destroy(eglWin) + delete(eglWindows.windows, surf) } - return &eglWindow{win}, nil } -func (w *eglWindow) window() _EGLNativeWindowType { - return w.w +func (w *window) eglDisplay() _EGLNativeDisplayType { + return w.display() } -func (w *eglWindow) resize(width, height int) { - C.wl_egl_window_resize(w.w, C.int(width), C.int(height), 0, 0) -} - -func (w *eglWindow) destroy() { - C.wl_egl_window_destroy(w.w) +func (w *window) eglWindow(visID int) (_EGLNativeWindowType, int, int, error) { + surf, width, height := w.surface() + if surf == nil { + return nilEGLNativeWindowType, 0, 0, errors.New("wayland: no surface") + } + eglWindows.mu.Lock() + defer eglWindows.mu.Unlock() + eglWin, ok := eglWindows.windows[surf] + if !ok { + if eglWindows.windows == nil { + eglWindows.windows = make(map[*C.struct_wl_surface]*C.struct_wl_egl_window) + } + eglWin = C.wl_egl_window_create(surf, C.int(width), C.int(height)) + if eglWin == nil { + return nilEGLNativeWindowType, 0, 0, errors.New("wayland: wl_egl_create_window failed") + } + eglWindows.windows[surf] = eglWin + } + C.wl_egl_window_resize(eglWin, C.int(width), C.int(height), 0, 0) + return eglWin, width, height, nil } func eglGetDisplay(disp _EGLNativeDisplayType) _EGLDisplay { diff --git a/app/egl_win.go b/app/egl_win.go deleted file mode 100644 index b7cb7cb3..00000000 --- a/app/egl_win.go +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -// +build android windows - -package app - -type eglWindow struct { - w _EGLNativeWindowType -} - -func newEGLWindow(w _EGLNativeWindowType, width, height int) (*eglWindow, error) { - return &eglWindow{w}, nil -} - -func (w *eglWindow) window() _EGLNativeWindowType { - return w.w -} - -func (w *eglWindow) resize(width, height int) {} -func (w *eglWindow) destroy() {} diff --git a/app/egl_windows.go b/app/egl_windows.go index cc49d43b..89260d62 100644 --- a/app/egl_windows.go +++ b/app/egl_windows.go @@ -142,3 +142,15 @@ func eglQueryString(disp _EGLDisplay, name _EGLint) string { r, _, _ := _eglQueryString.Call(uintptr(disp), uintptr(name)) return gl.GoString(gl.SliceOf(r)) } + +func (w *window) eglDestroy() { +} + +func (w *window) eglDisplay() _EGLNativeDisplayType { + return _EGLNativeDisplayType(w.HDC()) +} + +func (w *window) eglWindow(visID int) (_EGLNativeWindowType, int, int, error) { + hwnd, width, height := w.HWND() + return _EGLNativeWindowType(hwnd), width, height, nil +} diff --git a/app/os_android.go b/app/os_android.go index 1d86c39a..00901b01 100644 --- a/app/os_android.go +++ b/app/os_android.go @@ -245,11 +245,7 @@ func (w *window) setStage(stage Stage) { w.event(StageEvent{stage}) } -func (w *window) display() unsafe.Pointer { - return nil -} - -func (w *window) nativeWindow(visID int) (unsafe.Pointer, int, int) { +func (w *window) nativeWindow(visID int) (*C.ANativeWindow, int, int) { win := w.aNativeWindow() var width, height int if win != nil { @@ -259,7 +255,7 @@ func (w *window) nativeWindow(visID int) (unsafe.Pointer, int, int) { w, h := C.ANativeWindow_getWidth(win), C.ANativeWindow_getHeight(win) width, height = int(w), int(h) } - return unsafe.Pointer(win), width, height + return win, width, height } func (w *window) aNativeWindow() *C.ANativeWindow { diff --git a/app/os_wayland.go b/app/os_wayland.go index 248c7317..7bcb587b 100644 --- a/app/os_wayland.go +++ b/app/os_wayland.go @@ -1036,11 +1036,11 @@ func (w *window) setStage(s Stage) { w.w.event(StageEvent{s}) } -func (w *window) display() unsafe.Pointer { - return unsafe.Pointer(w.disp) +func (w *window) display() *C.struct_wl_display { + return w.disp } -func (w *window) nativeWindow(visID int) (unsafe.Pointer, int, int) { +func (w *window) surface() (*C.struct_wl_surface, int, int) { w.mu.Lock() defer w.mu.Unlock() if w.needAck { @@ -1052,7 +1052,7 @@ func (w *window) nativeWindow(visID int) (unsafe.Pointer, int, int) { C.wl_surface_set_buffer_scale(w.surf, C.int32_t(scale)) w.newScale = false } - return unsafe.Pointer(w.surf), width * scale, height * scale + return w.surf, width * scale, height * scale } func (w *window) showTextInput(show bool) {} diff --git a/app/os_windows.go b/app/os_windows.go index 096fd98c..abc1338a 100644 --- a/app/os_windows.go +++ b/app/os_windows.go @@ -430,12 +430,12 @@ func (w *window) destroy() { func (w *window) showTextInput(show bool) {} -func (w *window) display() uintptr { - return uintptr(w.hdc) +func (w *window) HDC() syscall.Handle { + return w.hdc } -func (w *window) nativeWindow(visID int) (uintptr, int, int) { - return uintptr(w.hwnd), w.width, w.height +func (w *window) HWND() (syscall.Handle, int, int) { + return w.hwnd, w.width, w.height } func convertKeyCode(code uintptr) (rune, bool) {