From 2dcbf6fe3c9e648c9c8ef049aa58ad4873ccb858 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 2 Oct 2019 23:07:54 +0200 Subject: [PATCH] app: confine the eglWindow indirection to the Wayland backend Only the Wayland backend needs an wl_egl_window between the wl_surface and EGL. Move code dealing with the indirection to Wayland specific code. Then, introduce the eglDriver interface instead of referencing the native window type directly. This will help when multiple backends are supported at runtime (e.g. Wayland+X11). Finally, move the eglDriver implementation methods from GOOS-specific code to separate EGL-specific files, allowing EGL types to be used directly instead of unsafe.Pointer and uinptr. The result is simpler generic EGL code, and easier path towards X11 support. Signed-off-by: Elias Naur --- app/egl.go | 61 ++++++++++++++++++++-------------------------- app/egl_android.go | 12 +++++++++ app/egl_wayland.go | 53 +++++++++++++++++++++++++++------------- app/egl_win.go | 20 --------------- app/egl_windows.go | 12 +++++++++ app/os_android.go | 8 ++---- app/os_wayland.go | 8 +++--- app/os_windows.go | 8 +++--- 8 files changed, 97 insertions(+), 85 deletions(-) delete mode 100644 app/egl_win.go 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) {