mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 01:45:36 +00:00
app/internal/window: move context refresh to window
Instead of calling from the low level context into the window for its surface and dimensions, add a Context.MakeCurrent method that does it directly. The result is simpler and clearer logic. For example, synchronization is obviously no longer needed. It wasn't necessary before, but the reason was unclear. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+48
-93
@@ -15,27 +15,15 @@ import (
|
|||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
c *gl.Functions
|
c *gl.Functions
|
||||||
driver Driver
|
disp _EGLDisplay
|
||||||
eglCtx *eglContext
|
eglCtx *eglContext
|
||||||
eglWin NativeWindowType
|
|
||||||
eglSurf _EGLSurface
|
eglSurf _EGLSurface
|
||||||
width, height int
|
width, height int
|
||||||
// For sRGB emulation.
|
// For sRGB emulation.
|
||||||
srgbFBO *gl.SRGBFBO
|
srgbFBO *gl.SRGBFBO
|
||||||
}
|
}
|
||||||
|
|
||||||
type Driver interface {
|
|
||||||
EGLDisplay() NativeDisplayType
|
|
||||||
EGLDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
type WindowDriver interface {
|
|
||||||
EGLWindow(visID int) (NativeWindowType, int, int, error)
|
|
||||||
NeedVSync() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type eglContext struct {
|
type eglContext struct {
|
||||||
disp _EGLDisplay
|
|
||||||
config _EGLConfig
|
config _EGLConfig
|
||||||
ctx _EGLContext
|
ctx _EGLContext
|
||||||
visualID int
|
visualID int
|
||||||
@@ -75,28 +63,20 @@ func (c *Context) Release() {
|
|||||||
c.srgbFBO.Release()
|
c.srgbFBO.Release()
|
||||||
c.srgbFBO = nil
|
c.srgbFBO = nil
|
||||||
}
|
}
|
||||||
c.destroySurface()
|
c.ReleaseSurface()
|
||||||
c.eglWin = nilEGLNativeWindowType
|
|
||||||
if c.eglCtx != nil {
|
if c.eglCtx != nil {
|
||||||
eglDestroyContext(c.eglCtx.disp, c.eglCtx.ctx)
|
eglDestroyContext(c.disp, c.eglCtx.ctx)
|
||||||
eglTerminate(c.eglCtx.disp)
|
eglTerminate(c.disp)
|
||||||
eglReleaseThread()
|
eglReleaseThread()
|
||||||
c.eglCtx = nil
|
c.eglCtx = nil
|
||||||
}
|
}
|
||||||
if c.driver != nil {
|
|
||||||
c.driver.EGLDestroy()
|
|
||||||
c.driver = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) Present() error {
|
func (c *Context) Present() error {
|
||||||
if c.eglWin == nilEGLNativeWindowType {
|
|
||||||
panic("context is not active")
|
|
||||||
}
|
|
||||||
if c.srgbFBO != nil {
|
if c.srgbFBO != nil {
|
||||||
c.srgbFBO.Blit()
|
c.srgbFBO.Blit()
|
||||||
}
|
}
|
||||||
if !eglSwapBuffers(c.eglCtx.disp, c.eglSurf) {
|
if !eglSwapBuffers(c.disp, c.eglSurf) {
|
||||||
return fmt.Errorf("eglSwapBuffers failed (%x)", eglGetError())
|
return fmt.Errorf("eglSwapBuffers failed (%x)", eglGetError())
|
||||||
}
|
}
|
||||||
if c.srgbFBO != nil {
|
if c.srgbFBO != nil {
|
||||||
@@ -105,17 +85,17 @@ func (c *Context) Present() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContext(d Driver) (*Context, error) {
|
func NewContext(disp NativeDisplayType) (*Context, error) {
|
||||||
eglCtx, err := createContext(d.EGLDisplay())
|
eglDisp := eglGetDisplay(disp)
|
||||||
|
if eglDisp == nilEGLDisplay {
|
||||||
|
return nil, fmt.Errorf("eglGetDisplay failed: 0x%x", eglGetError())
|
||||||
|
}
|
||||||
|
eglCtx, err := createContext(eglDisp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if _, windowed := d.(WindowDriver); !windowed && !eglCtx.surfaceless {
|
|
||||||
eglDestroyContext(eglCtx.disp, eglCtx.ctx)
|
|
||||||
return nil, errors.New("EGL_KHR_surfaceless_context not supported")
|
|
||||||
}
|
|
||||||
c := &Context{
|
c := &Context{
|
||||||
driver: d,
|
disp: eglDisp,
|
||||||
eglCtx: eglCtx,
|
eglCtx: eglCtx,
|
||||||
c: new(gl.Functions),
|
c: new(gl.Functions),
|
||||||
}
|
}
|
||||||
@@ -130,59 +110,36 @@ func (c *Context) Lock() {}
|
|||||||
|
|
||||||
func (c *Context) Unlock() {}
|
func (c *Context) Unlock() {}
|
||||||
|
|
||||||
func (c *Context) destroySurface() {
|
func (c *Context) ReleaseSurface() {
|
||||||
if c.eglSurf == nilEGLSurface {
|
if c.eglSurf == nilEGLSurface {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Make sure any in-flight GL commands are complete.
|
// Make sure any in-flight GL commands are complete.
|
||||||
c.c.Finish()
|
c.c.Finish()
|
||||||
eglMakeCurrent(c.eglCtx.disp, nilEGLSurface, nilEGLSurface, nilEGLContext)
|
eglMakeCurrent(c.disp, nilEGLSurface, nilEGLSurface, nilEGLContext)
|
||||||
eglDestroySurface(c.eglCtx.disp, c.eglSurf)
|
eglDestroySurface(c.disp, c.eglSurf)
|
||||||
c.eglSurf = nilEGLSurface
|
c.eglSurf = nilEGLSurface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) MakeCurrent() error {
|
func (c *Context) VisualID() int {
|
||||||
wdriver, ok := c.driver.(WindowDriver)
|
return c.eglCtx.visualID
|
||||||
if !ok {
|
}
|
||||||
if !eglMakeCurrent(c.eglCtx.disp, nilEGLSurface, nilEGLSurface, c.eglCtx.ctx) {
|
|
||||||
return fmt.Errorf("eglMakeCurrent error 0x%x", eglGetError())
|
func (c *Context) CreateSurface(win NativeWindowType, width, height int) error {
|
||||||
}
|
eglSurf, err := createSurface(c.disp, c.eglCtx, win)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
win, width, height, err := wdriver.EGLWindow(int(c.eglCtx.visualID))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if c.eglWin == win && width == c.width && height == c.height {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
c.width, c.height = width, height
|
|
||||||
if win == nilEGLNativeWindowType && c.srgbFBO != nil {
|
|
||||||
c.srgbFBO.Release()
|
|
||||||
c.srgbFBO = nil
|
|
||||||
}
|
|
||||||
c.destroySurface()
|
|
||||||
c.eglWin = win
|
|
||||||
if c.eglWin == nilEGLNativeWindowType {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
eglSurf, err := createSurface(c.eglCtx, win)
|
|
||||||
c.eglSurf = eglSurf
|
c.eglSurf = eglSurf
|
||||||
if err != nil {
|
c.width = width
|
||||||
c.eglWin = nilEGLNativeWindowType
|
c.height = height
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) MakeCurrent() error {
|
||||||
|
if c.eglSurf == nilEGLSurface && !c.eglCtx.surfaceless {
|
||||||
|
return errors.New("no surface created yet EGL_KHR_surfaceless_context is not supported")
|
||||||
}
|
}
|
||||||
if !eglMakeCurrent(c.eglCtx.disp, eglSurf, eglSurf, c.eglCtx.ctx) {
|
if !eglMakeCurrent(c.disp, c.eglSurf, c.eglSurf, c.eglCtx.ctx) {
|
||||||
return fmt.Errorf("eglMakeCurrent error 0x%x", eglGetError())
|
return fmt.Errorf("eglMakeCurrent error 0x%x", eglGetError())
|
||||||
}
|
}
|
||||||
// eglSwapInterval 1 leads to erratic frame rates and unnecessary blocking.
|
|
||||||
// We rely on platform specific frame rate limiting instead, except on Windows
|
|
||||||
// and X11 where eglSwapInterval is all there is.
|
|
||||||
if wdriver.NeedVSync() {
|
|
||||||
eglSwapInterval(c.eglCtx.disp, 1)
|
|
||||||
} else {
|
|
||||||
eglSwapInterval(c.eglCtx.disp, 0)
|
|
||||||
}
|
|
||||||
if c.eglCtx.srgb {
|
if c.eglCtx.srgb {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -190,15 +147,18 @@ func (c *Context) MakeCurrent() error {
|
|||||||
var err error
|
var err error
|
||||||
c.srgbFBO, err = gl.NewSRGBFBO(c.c)
|
c.srgbFBO, err = gl.NewSRGBFBO(c.c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Release()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := c.srgbFBO.Refresh(c.width, c.height); err != nil {
|
return c.srgbFBO.Refresh(c.width, c.height)
|
||||||
c.Release()
|
}
|
||||||
return err
|
|
||||||
|
func (c *Context) EnableVSync(enable bool) {
|
||||||
|
if enable {
|
||||||
|
eglSwapInterval(c.disp, 1)
|
||||||
|
} else {
|
||||||
|
eglSwapInterval(c.disp, 0)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasExtension(exts []string, ext string) bool {
|
func hasExtension(exts []string, ext string) bool {
|
||||||
@@ -210,17 +170,13 @@ func hasExtension(exts []string, ext string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func createContext(disp NativeDisplayType) (*eglContext, error) {
|
func createContext(disp _EGLDisplay) (*eglContext, error) {
|
||||||
eglDisp := eglGetDisplay(disp)
|
major, minor, ret := eglInitialize(disp)
|
||||||
if eglDisp == nilEGLDisplay {
|
|
||||||
return nil, fmt.Errorf("eglGetDisplay(_EGL_DEFAULT_DISPLAY) failed: 0x%x", eglGetError())
|
|
||||||
}
|
|
||||||
major, minor, ret := eglInitialize(eglDisp)
|
|
||||||
if !ret {
|
if !ret {
|
||||||
return nil, fmt.Errorf("eglInitialize failed: 0x%x", eglGetError())
|
return nil, fmt.Errorf("eglInitialize failed: 0x%x", eglGetError())
|
||||||
}
|
}
|
||||||
// sRGB framebuffer support on EGL 1.5 or if EGL_KHR_gl_colorspace is supported.
|
// sRGB framebuffer support on EGL 1.5 or if EGL_KHR_gl_colorspace is supported.
|
||||||
exts := strings.Split(eglQueryString(eglDisp, _EGL_EXTENSIONS), " ")
|
exts := strings.Split(eglQueryString(disp, _EGL_EXTENSIONS), " ")
|
||||||
srgb := major > 1 || minor >= 5 || hasExtension(exts, "EGL_KHR_gl_colorspace")
|
srgb := major > 1 || minor >= 5 || hasExtension(exts, "EGL_KHR_gl_colorspace")
|
||||||
attribs := []_EGLint{
|
attribs := []_EGLint{
|
||||||
_EGL_RENDERABLE_TYPE, _EGL_OPENGL_ES2_BIT,
|
_EGL_RENDERABLE_TYPE, _EGL_OPENGL_ES2_BIT,
|
||||||
@@ -240,14 +196,14 @@ func createContext(disp NativeDisplayType) (*eglContext, error) {
|
|||||||
attribs = append(attribs, _EGL_DEPTH_SIZE, 16)
|
attribs = append(attribs, _EGL_DEPTH_SIZE, 16)
|
||||||
}
|
}
|
||||||
attribs = append(attribs, _EGL_NONE)
|
attribs = append(attribs, _EGL_NONE)
|
||||||
eglCfg, ret := eglChooseConfig(eglDisp, attribs)
|
eglCfg, ret := eglChooseConfig(disp, attribs)
|
||||||
if !ret {
|
if !ret {
|
||||||
return nil, fmt.Errorf("eglChooseConfig failed: 0x%x", eglGetError())
|
return nil, fmt.Errorf("eglChooseConfig failed: 0x%x", eglGetError())
|
||||||
}
|
}
|
||||||
if eglCfg == nilEGLConfig {
|
if eglCfg == nilEGLConfig {
|
||||||
return nil, errors.New("eglChooseConfig returned 0 configs")
|
return nil, errors.New("eglChooseConfig returned 0 configs")
|
||||||
}
|
}
|
||||||
visID, ret := eglGetConfigAttrib(eglDisp, eglCfg, _EGL_NATIVE_VISUAL_ID)
|
visID, ret := eglGetConfigAttrib(disp, eglCfg, _EGL_NATIVE_VISUAL_ID)
|
||||||
if !ret {
|
if !ret {
|
||||||
return nil, errors.New("newContext: eglGetConfigAttrib for _EGL_NATIVE_VISUAL_ID failed")
|
return nil, errors.New("newContext: eglGetConfigAttrib for _EGL_NATIVE_VISUAL_ID failed")
|
||||||
}
|
}
|
||||||
@@ -255,20 +211,19 @@ func createContext(disp NativeDisplayType) (*eglContext, error) {
|
|||||||
_EGL_CONTEXT_CLIENT_VERSION, 3,
|
_EGL_CONTEXT_CLIENT_VERSION, 3,
|
||||||
_EGL_NONE,
|
_EGL_NONE,
|
||||||
}
|
}
|
||||||
eglCtx := eglCreateContext(eglDisp, eglCfg, nilEGLContext, ctxAttribs)
|
eglCtx := eglCreateContext(disp, eglCfg, nilEGLContext, ctxAttribs)
|
||||||
if eglCtx == nilEGLContext {
|
if eglCtx == nilEGLContext {
|
||||||
// Fall back to OpenGL ES 2 and rely on extensions.
|
// Fall back to OpenGL ES 2 and rely on extensions.
|
||||||
ctxAttribs := []_EGLint{
|
ctxAttribs := []_EGLint{
|
||||||
_EGL_CONTEXT_CLIENT_VERSION, 2,
|
_EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||||
_EGL_NONE,
|
_EGL_NONE,
|
||||||
}
|
}
|
||||||
eglCtx = eglCreateContext(eglDisp, eglCfg, nilEGLContext, ctxAttribs)
|
eglCtx = eglCreateContext(disp, eglCfg, nilEGLContext, ctxAttribs)
|
||||||
if eglCtx == nilEGLContext {
|
if eglCtx == nilEGLContext {
|
||||||
return nil, fmt.Errorf("eglCreateContext failed: 0x%x", eglGetError())
|
return nil, fmt.Errorf("eglCreateContext failed: 0x%x", eglGetError())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &eglContext{
|
return &eglContext{
|
||||||
disp: eglDisp,
|
|
||||||
config: _EGLConfig(eglCfg),
|
config: _EGLConfig(eglCfg),
|
||||||
ctx: _EGLContext(eglCtx),
|
ctx: _EGLContext(eglCtx),
|
||||||
visualID: int(visID),
|
visualID: int(visID),
|
||||||
@@ -277,18 +232,18 @@ func createContext(disp NativeDisplayType) (*eglContext, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSurface(eglCtx *eglContext, win NativeWindowType) (_EGLSurface, error) {
|
func createSurface(disp _EGLDisplay, eglCtx *eglContext, win NativeWindowType) (_EGLSurface, error) {
|
||||||
var surfAttribs []_EGLint
|
var surfAttribs []_EGLint
|
||||||
if eglCtx.srgb {
|
if eglCtx.srgb {
|
||||||
surfAttribs = append(surfAttribs, _EGL_GL_COLORSPACE_KHR, _EGL_GL_COLORSPACE_SRGB_KHR)
|
surfAttribs = append(surfAttribs, _EGL_GL_COLORSPACE_KHR, _EGL_GL_COLORSPACE_SRGB_KHR)
|
||||||
}
|
}
|
||||||
surfAttribs = append(surfAttribs, _EGL_NONE)
|
surfAttribs = append(surfAttribs, _EGL_NONE)
|
||||||
eglSurf := eglCreateWindowSurface(eglCtx.disp, eglCtx.config, win, surfAttribs)
|
eglSurf := eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs)
|
||||||
if eglSurf == nilEGLSurface && eglCtx.srgb {
|
if eglSurf == nilEGLSurface && eglCtx.srgb {
|
||||||
// Try again without sRGB
|
// Try again without sRGB
|
||||||
eglCtx.srgb = false
|
eglCtx.srgb = false
|
||||||
surfAttribs = []_EGLint{_EGL_NONE}
|
surfAttribs = []_EGLint{_EGL_NONE}
|
||||||
eglSurf = eglCreateWindowSurface(eglCtx.disp, eglCtx.config, win, surfAttribs)
|
eglSurf = eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs)
|
||||||
}
|
}
|
||||||
if eglSurf == nilEGLSurface {
|
if eglSurf == nilEGLSurface {
|
||||||
return nilEGLSurface, fmt.Errorf("newContext: eglCreateWindowSurface failed 0x%x (sRGB=%v)", eglGetError(), eglCtx.srgb)
|
return nilEGLSurface, fmt.Errorf("newContext: eglCreateWindowSurface failed 0x%x (sRGB=%v)", eglGetError(), eglCtx.srgb)
|
||||||
|
|||||||
@@ -14,20 +14,38 @@ import (
|
|||||||
"gioui.org/app/internal/gl"
|
"gioui.org/app/internal/gl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (w *window) EGLDestroy() {
|
type context struct {
|
||||||
}
|
win *window
|
||||||
|
*egl.Context
|
||||||
func (w *window) EGLDisplay() egl.NativeDisplayType {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *window) EGLWindow(visID int) (egl.NativeWindowType, int, int, error) {
|
|
||||||
win, width, height := w.nativeWindow(visID)
|
|
||||||
return egl.NativeWindowType(unsafe.Pointer(win)), width, height, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) NewContext() (gl.Context, error) {
|
func (w *window) NewContext() (gl.Context, error) {
|
||||||
return egl.NewContext(w)
|
ctx, err := egl.NewContext(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &context{win: w, Context: ctx}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) NeedVSync() bool { return false }
|
func (c *context) Release() {
|
||||||
|
if c.Context != nil {
|
||||||
|
c.Context.Release()
|
||||||
|
c.Context = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) MakeCurrent() error {
|
||||||
|
c.Context.ReleaseSurface()
|
||||||
|
win, width, height := c.win.nativeWindow(c.Context.VisualID())
|
||||||
|
if win == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
eglSurf := egl.NativeWindowType(unsafe.Pointer(win))
|
||||||
|
if err := c.Context.CreateSurface(eglSurf, width, height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.Context.MakeCurrent(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package window
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"gioui.org/app/internal/egl"
|
"gioui.org/app/internal/egl"
|
||||||
@@ -22,52 +21,50 @@ import (
|
|||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var eglWindows struct {
|
type context struct {
|
||||||
mu sync.Mutex
|
win *window
|
||||||
windows map[*C.struct_wl_surface]*C.struct_wl_egl_window
|
*egl.Context
|
||||||
}
|
eglWin *C.struct_wl_egl_window
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *window) EGLDisplay() egl.NativeDisplayType {
|
|
||||||
return egl.NativeDisplayType(unsafe.Pointer(w.display()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *window) EGLWindow(visID int) (egl.NativeWindowType, int, int, error) {
|
|
||||||
surf, width, height := w.surface()
|
|
||||||
if surf == nil {
|
|
||||||
return 0, 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 0, 0, 0, errors.New("wayland: wl_egl_window_create failed")
|
|
||||||
}
|
|
||||||
eglWindows.windows[surf] = eglWin
|
|
||||||
}
|
|
||||||
C.wl_egl_window_resize(eglWin, C.int(width), C.int(height), 0, 0)
|
|
||||||
return egl.NativeWindowType(uintptr(unsafe.Pointer(eglWin))), width, height, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) NewContext() (gl.Context, error) {
|
func (w *window) NewContext() (gl.Context, error) {
|
||||||
return egl.NewContext(w)
|
disp := egl.NativeDisplayType(unsafe.Pointer(w.display()))
|
||||||
|
ctx, err := egl.NewContext(disp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &context{Context: ctx, win: w}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) NeedVSync() bool { return false }
|
func (c *context) Release() {
|
||||||
|
if c.Context != nil {
|
||||||
|
c.Context.Release()
|
||||||
|
c.Context = nil
|
||||||
|
}
|
||||||
|
if c.eglWin != nil {
|
||||||
|
C.wl_egl_window_destroy(c.eglWin)
|
||||||
|
c.eglWin = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) MakeCurrent() error {
|
||||||
|
c.Context.ReleaseSurface()
|
||||||
|
if c.eglWin != nil {
|
||||||
|
C.wl_egl_window_destroy(c.eglWin)
|
||||||
|
c.eglWin = nil
|
||||||
|
}
|
||||||
|
surf, width, height := c.win.surface()
|
||||||
|
if surf == nil {
|
||||||
|
return errors.New("wayland: no surface")
|
||||||
|
}
|
||||||
|
eglWin := C.wl_egl_window_create(surf, C.int(width), C.int(height))
|
||||||
|
if eglWin == nil {
|
||||||
|
return errors.New("wayland: wl_egl_window_create failed")
|
||||||
|
}
|
||||||
|
c.eglWin = eglWin
|
||||||
|
eglSurf := egl.NativeWindowType(uintptr(unsafe.Pointer(eglWin)))
|
||||||
|
if err := c.Context.CreateSurface(eglSurf, width, height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Context.MakeCurrent()
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,24 +3,43 @@
|
|||||||
package window
|
package window
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"gioui.org/app/internal/egl"
|
"gioui.org/app/internal/egl"
|
||||||
"gioui.org/app/internal/gl"
|
"gioui.org/app/internal/gl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (w *window) EGLDestroy() {
|
type context struct {
|
||||||
}
|
win *window
|
||||||
|
*egl.Context
|
||||||
func (w *window) EGLDisplay() egl.NativeDisplayType {
|
|
||||||
return egl.NativeDisplayType(w.HDC())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *window) EGLWindow(visID int) (egl.NativeWindowType, int, int, error) {
|
|
||||||
hwnd, width, height := w.HWND()
|
|
||||||
return egl.NativeWindowType(hwnd), width, height, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) NewContext() (gl.Context, error) {
|
func (w *window) NewContext() (gl.Context, error) {
|
||||||
return egl.NewContext(w)
|
disp := egl.NativeDisplayType(unsafe.Pointer(w.HDC()))
|
||||||
|
ctx, err := egl.NewContext(disp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &context{win: w, Context: ctx}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) NeedVSync() bool { return true }
|
func (c *context) Release() {
|
||||||
|
if c.Context != nil {
|
||||||
|
c.Context.Release()
|
||||||
|
c.Context = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) MakeCurrent() error {
|
||||||
|
c.Context.ReleaseSurface()
|
||||||
|
win, width, height := c.win.HWND()
|
||||||
|
eglSurf := egl.NativeWindowType(win)
|
||||||
|
if err := c.Context.CreateSurface(eglSurf, width, height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.Context.MakeCurrent(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Context.EnableVSync(true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,23 +5,43 @@
|
|||||||
package window
|
package window
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"gioui.org/app/internal/egl"
|
"gioui.org/app/internal/egl"
|
||||||
"gioui.org/app/internal/gl"
|
"gioui.org/app/internal/gl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type x11Context struct {
|
||||||
|
win *x11Window
|
||||||
|
*egl.Context
|
||||||
|
}
|
||||||
|
|
||||||
func (w *x11Window) NewContext() (gl.Context, error) {
|
func (w *x11Window) NewContext() (gl.Context, error) {
|
||||||
return egl.NewContext(w)
|
disp := egl.NativeDisplayType(unsafe.Pointer(w.display()))
|
||||||
|
ctx, err := egl.NewContext(disp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &x11Context{win: w, Context: ctx}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *x11Window) EGLDestroy() {
|
func (c *x11Context) Release() {
|
||||||
|
if c.Context != nil {
|
||||||
|
c.Context.Release()
|
||||||
|
c.Context = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *x11Window) EGLDisplay() egl.NativeDisplayType {
|
func (c *x11Context) MakeCurrent() error {
|
||||||
return egl.NativeDisplayType(w.display())
|
c.Context.ReleaseSurface()
|
||||||
|
win, width, height := c.win.window()
|
||||||
|
eglSurf := egl.NativeWindowType(uintptr(win))
|
||||||
|
if err := c.Context.CreateSurface(eglSurf, width, height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.Context.MakeCurrent(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Context.EnableVSync(true)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *x11Window) EGLWindow(visID int) (egl.NativeWindowType, int, int, error) {
|
|
||||||
return egl.NativeWindowType(uintptr(w.xw)), w.width, w.height, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *x11Window) NeedVSync() bool { return true }
|
|
||||||
|
|||||||
@@ -1052,8 +1052,6 @@ func (w *window) display() *C.struct_wl_display {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) surface() (*C.struct_wl_surface, int, int) {
|
func (w *window) surface() (*C.struct_wl_surface, int, int) {
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
if w.needAck {
|
if w.needAck {
|
||||||
C.xdg_surface_ack_configure(w.wmSurf, w.serial)
|
C.xdg_surface_ack_configure(w.wmSurf, w.serial)
|
||||||
w.needAck = false
|
w.needAck = false
|
||||||
|
|||||||
@@ -78,8 +78,12 @@ func (w *x11Window) wakeup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *x11Window) display() unsafe.Pointer {
|
func (w *x11Window) display() *C.Display {
|
||||||
return unsafe.Pointer(w.x)
|
return w.x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *x11Window) window() (C.Window, int, int) {
|
||||||
|
return w.xw, w.width, w.height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *x11Window) setStage(s system.Stage) {
|
func (w *x11Window) setStage(s system.Stage) {
|
||||||
|
|||||||
Reference in New Issue
Block a user