diff options
Diffstat (limited to 'vendor/gioui.org/internal/egl')
-rw-r--r-- | vendor/gioui.org/internal/egl/egl.go | 253 | ||||
-rw-r--r-- | vendor/gioui.org/internal/egl/egl_unix.go | 109 | ||||
-rw-r--r-- | vendor/gioui.org/internal/egl/egl_windows.go | 169 |
3 files changed, 531 insertions, 0 deletions
diff --git a/vendor/gioui.org/internal/egl/egl.go b/vendor/gioui.org/internal/egl/egl.go new file mode 100644 index 0000000..7d7b551 --- /dev/null +++ b/vendor/gioui.org/internal/egl/egl.go @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build linux || windows || freebsd || openbsd +// +build linux windows freebsd openbsd + +package egl + +import ( + "errors" + "fmt" + "runtime" + "strings" + + "gioui.org/gpu" +) + +type Context struct { + disp _EGLDisplay + eglCtx *eglContext + eglSurf _EGLSurface + width, height int +} + +type eglContext struct { + config _EGLConfig + ctx _EGLContext + visualID int + srgb bool + surfaceless bool +} + +var ( + nilEGLDisplay _EGLDisplay + nilEGLSurface _EGLSurface + nilEGLContext _EGLContext + nilEGLConfig _EGLConfig + EGL_DEFAULT_DISPLAY NativeDisplayType +) + +const ( + _EGL_ALPHA_SIZE = 0x3021 + _EGL_BLUE_SIZE = 0x3022 + _EGL_CONFIG_CAVEAT = 0x3027 + _EGL_CONTEXT_CLIENT_VERSION = 0x3098 + _EGL_DEPTH_SIZE = 0x3025 + _EGL_GL_COLORSPACE_KHR = 0x309d + _EGL_GL_COLORSPACE_SRGB_KHR = 0x3089 + _EGL_GREEN_SIZE = 0x3023 + _EGL_EXTENSIONS = 0x3055 + _EGL_NATIVE_VISUAL_ID = 0x302e + _EGL_NONE = 0x3038 + _EGL_OPENGL_ES2_BIT = 0x4 + _EGL_RED_SIZE = 0x3024 + _EGL_RENDERABLE_TYPE = 0x3040 + _EGL_SURFACE_TYPE = 0x3033 + _EGL_WINDOW_BIT = 0x4 +) + +func (c *Context) Release() { + c.ReleaseSurface() + if c.eglCtx != nil { + eglDestroyContext(c.disp, c.eglCtx.ctx) + c.eglCtx = nil + } + c.disp = nilEGLDisplay +} + +func (c *Context) Present() error { + if !eglSwapBuffers(c.disp, c.eglSurf) { + return fmt.Errorf("eglSwapBuffers failed (%x)", eglGetError()) + } + return nil +} + +func NewContext(disp NativeDisplayType) (*Context, error) { + if err := loadEGL(); err != nil { + return nil, err + } + eglDisp := eglGetDisplay(disp) + // eglGetDisplay can return EGL_NO_DISPLAY yet no error + // (EGL_SUCCESS), in which case a default EGL display might be + // available. + if eglDisp == nilEGLDisplay { + eglDisp = eglGetDisplay(EGL_DEFAULT_DISPLAY) + } + if eglDisp == nilEGLDisplay { + return nil, fmt.Errorf("eglGetDisplay failed: 0x%x", eglGetError()) + } + eglCtx, err := createContext(eglDisp) + if err != nil { + return nil, err + } + c := &Context{ + disp: eglDisp, + eglCtx: eglCtx, + } + return c, nil +} + +func (c *Context) RenderTarget() (gpu.RenderTarget, error) { + return gpu.OpenGLRenderTarget{}, nil +} + +func (c *Context) API() gpu.API { + return gpu.OpenGL{} +} + +func (c *Context) ReleaseSurface() { + if c.eglSurf == nilEGLSurface { + return + } + // Make sure any in-flight GL commands are complete. + eglWaitClient() + c.ReleaseCurrent() + eglDestroySurface(c.disp, c.eglSurf) + c.eglSurf = nilEGLSurface +} + +func (c *Context) VisualID() int { + return c.eglCtx.visualID +} + +func (c *Context) CreateSurface(win NativeWindowType, width, height int) error { + eglSurf, err := createSurface(c.disp, c.eglCtx, win) + c.eglSurf = eglSurf + c.width = width + c.height = height + return err +} + +func (c *Context) ReleaseCurrent() { + if c.disp != nilEGLDisplay { + eglMakeCurrent(c.disp, nilEGLSurface, nilEGLSurface, nilEGLContext) + } +} + +func (c *Context) MakeCurrent() error { + // OpenGL contexts are implicit and thread-local. Lock the OS thread. + runtime.LockOSThread() + + if c.eglSurf == nilEGLSurface && !c.eglCtx.surfaceless { + return errors.New("no surface created yet EGL_KHR_surfaceless_context is not supported") + } + if !eglMakeCurrent(c.disp, c.eglSurf, c.eglSurf, c.eglCtx.ctx) { + return fmt.Errorf("eglMakeCurrent error 0x%x", eglGetError()) + } + return nil +} + +func (c *Context) EnableVSync(enable bool) { + if enable { + eglSwapInterval(c.disp, 1) + } else { + eglSwapInterval(c.disp, 0) + } +} + +func hasExtension(exts []string, ext string) bool { + for _, e := range exts { + if ext == e { + return true + } + } + return false +} + +func createContext(disp _EGLDisplay) (*eglContext, error) { + major, minor, ret := eglInitialize(disp) + if !ret { + return nil, fmt.Errorf("eglInitialize failed: 0x%x", eglGetError()) + } + // sRGB framebuffer support on EGL 1.5 or if EGL_KHR_gl_colorspace is supported. + exts := strings.Split(eglQueryString(disp, _EGL_EXTENSIONS), " ") + srgb := major > 1 || minor >= 5 || hasExtension(exts, "EGL_KHR_gl_colorspace") + attribs := []_EGLint{ + _EGL_RENDERABLE_TYPE, _EGL_OPENGL_ES2_BIT, + _EGL_SURFACE_TYPE, _EGL_WINDOW_BIT, + _EGL_BLUE_SIZE, 8, + _EGL_GREEN_SIZE, 8, + _EGL_RED_SIZE, 8, + _EGL_CONFIG_CAVEAT, _EGL_NONE, + } + if srgb { + if runtime.GOOS == "linux" || runtime.GOOS == "android" { + // Some Mesa drivers crash if an sRGB framebuffer is requested without alpha. + // https://bugs.freedesktop.org/show_bug.cgi?id=107782. + // + // Also, some Android devices (Samsung S9) need alpha for sRGB to work. + attribs = append(attribs, _EGL_ALPHA_SIZE, 8) + } + } + attribs = append(attribs, _EGL_NONE) + eglCfg, ret := eglChooseConfig(disp, attribs) + if !ret { + return nil, fmt.Errorf("eglChooseConfig failed: 0x%x", eglGetError()) + } + if eglCfg == nilEGLConfig { + supportsNoCfg := hasExtension(exts, "EGL_KHR_no_config_context") + if !supportsNoCfg { + return nil, errors.New("eglChooseConfig returned no configs") + } + } + var visID _EGLint + if eglCfg != nilEGLConfig { + var ok bool + visID, ok = eglGetConfigAttrib(disp, eglCfg, _EGL_NATIVE_VISUAL_ID) + if !ok { + return nil, errors.New("newContext: eglGetConfigAttrib for _EGL_NATIVE_VISUAL_ID failed") + } + } + ctxAttribs := []_EGLint{ + _EGL_CONTEXT_CLIENT_VERSION, 3, + _EGL_NONE, + } + eglCtx := eglCreateContext(disp, eglCfg, nilEGLContext, ctxAttribs) + if eglCtx == nilEGLContext { + // Fall back to OpenGL ES 2 and rely on extensions. + ctxAttribs := []_EGLint{ + _EGL_CONTEXT_CLIENT_VERSION, 2, + _EGL_NONE, + } + eglCtx = eglCreateContext(disp, eglCfg, nilEGLContext, ctxAttribs) + if eglCtx == nilEGLContext { + return nil, fmt.Errorf("eglCreateContext failed: 0x%x", eglGetError()) + } + } + return &eglContext{ + config: _EGLConfig(eglCfg), + ctx: _EGLContext(eglCtx), + visualID: int(visID), + srgb: srgb, + surfaceless: hasExtension(exts, "EGL_KHR_surfaceless_context"), + }, nil +} + +func createSurface(disp _EGLDisplay, eglCtx *eglContext, win NativeWindowType) (_EGLSurface, error) { + var surfAttribs []_EGLint + if eglCtx.srgb { + surfAttribs = append(surfAttribs, _EGL_GL_COLORSPACE_KHR, _EGL_GL_COLORSPACE_SRGB_KHR) + } + surfAttribs = append(surfAttribs, _EGL_NONE) + eglSurf := eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs) + if eglSurf == nilEGLSurface && eglCtx.srgb { + // Try again without sRGB. + eglCtx.srgb = false + surfAttribs = []_EGLint{_EGL_NONE} + eglSurf = eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs) + } + if eglSurf == nilEGLSurface { + return nilEGLSurface, fmt.Errorf("newContext: eglCreateWindowSurface failed 0x%x (sRGB=%v)", eglGetError(), eglCtx.srgb) + } + return eglSurf, nil +} diff --git a/vendor/gioui.org/internal/egl/egl_unix.go b/vendor/gioui.org/internal/egl/egl_unix.go new file mode 100644 index 0000000..bd3efa5 --- /dev/null +++ b/vendor/gioui.org/internal/egl/egl_unix.go @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build linux || freebsd || openbsd +// +build linux freebsd openbsd + +package egl + +/* +#cgo linux,!android pkg-config: egl +#cgo freebsd openbsd android LDFLAGS: -lEGL +#cgo freebsd CFLAGS: -I/usr/local/include +#cgo freebsd LDFLAGS: -L/usr/local/lib +#cgo openbsd CFLAGS: -I/usr/X11R6/include +#cgo openbsd LDFLAGS: -L/usr/X11R6/lib +#cgo CFLAGS: -DEGL_NO_X11 + +#include <EGL/egl.h> +#include <EGL/eglext.h> +*/ +import "C" + +type ( + _EGLint = C.EGLint + _EGLDisplay = C.EGLDisplay + _EGLConfig = C.EGLConfig + _EGLContext = C.EGLContext + _EGLSurface = C.EGLSurface + NativeDisplayType = C.EGLNativeDisplayType + NativeWindowType = C.EGLNativeWindowType +) + +func loadEGL() error { + return nil +} + +func eglChooseConfig(disp _EGLDisplay, attribs []_EGLint) (_EGLConfig, bool) { + var cfg C.EGLConfig + var ncfg C.EGLint + if C.eglChooseConfig(disp, &attribs[0], &cfg, 1, &ncfg) != C.EGL_TRUE { + return nilEGLConfig, false + } + return _EGLConfig(cfg), true +} + +func eglCreateContext(disp _EGLDisplay, cfg _EGLConfig, shareCtx _EGLContext, attribs []_EGLint) _EGLContext { + ctx := C.eglCreateContext(disp, cfg, shareCtx, &attribs[0]) + return _EGLContext(ctx) +} + +func eglDestroySurface(disp _EGLDisplay, surf _EGLSurface) bool { + return C.eglDestroySurface(disp, surf) == C.EGL_TRUE +} + +func eglDestroyContext(disp _EGLDisplay, ctx _EGLContext) bool { + return C.eglDestroyContext(disp, ctx) == C.EGL_TRUE +} + +func eglGetConfigAttrib(disp _EGLDisplay, cfg _EGLConfig, attr _EGLint) (_EGLint, bool) { + var val _EGLint + ret := C.eglGetConfigAttrib(disp, cfg, attr, &val) + return val, ret == C.EGL_TRUE +} + +func eglGetError() _EGLint { + return C.eglGetError() +} + +func eglInitialize(disp _EGLDisplay) (_EGLint, _EGLint, bool) { + var maj, min _EGLint + ret := C.eglInitialize(disp, &maj, &min) + return maj, min, ret == C.EGL_TRUE +} + +func eglMakeCurrent(disp _EGLDisplay, draw, read _EGLSurface, ctx _EGLContext) bool { + return C.eglMakeCurrent(disp, draw, read, ctx) == C.EGL_TRUE +} + +func eglReleaseThread() bool { + return C.eglReleaseThread() == C.EGL_TRUE +} + +func eglSwapBuffers(disp _EGLDisplay, surf _EGLSurface) bool { + return C.eglSwapBuffers(disp, surf) == C.EGL_TRUE +} + +func eglSwapInterval(disp _EGLDisplay, interval _EGLint) bool { + return C.eglSwapInterval(disp, interval) == C.EGL_TRUE +} + +func eglTerminate(disp _EGLDisplay) bool { + return C.eglTerminate(disp) == C.EGL_TRUE +} + +func eglQueryString(disp _EGLDisplay, name _EGLint) string { + return C.GoString(C.eglQueryString(disp, name)) +} + +func eglGetDisplay(disp NativeDisplayType) _EGLDisplay { + return C.eglGetDisplay(disp) +} + +func eglCreateWindowSurface(disp _EGLDisplay, conf _EGLConfig, win NativeWindowType, attribs []_EGLint) _EGLSurface { + eglSurf := C.eglCreateWindowSurface(disp, conf, win, &attribs[0]) + return eglSurf +} + +func eglWaitClient() bool { + return C.eglWaitClient() == C.EGL_TRUE +} diff --git a/vendor/gioui.org/internal/egl/egl_windows.go b/vendor/gioui.org/internal/egl/egl_windows.go new file mode 100644 index 0000000..4433dd7 --- /dev/null +++ b/vendor/gioui.org/internal/egl/egl_windows.go @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package egl + +import ( + "fmt" + "runtime" + "sync" + "unsafe" + + syscall "golang.org/x/sys/windows" + + "gioui.org/internal/gl" +) + +type ( + _EGLint int32 + _EGLDisplay uintptr + _EGLConfig uintptr + _EGLContext uintptr + _EGLSurface uintptr + NativeDisplayType uintptr + NativeWindowType uintptr +) + +var ( + libEGL = syscall.NewLazyDLL("libEGL.dll") + _eglChooseConfig = libEGL.NewProc("eglChooseConfig") + _eglCreateContext = libEGL.NewProc("eglCreateContext") + _eglCreateWindowSurface = libEGL.NewProc("eglCreateWindowSurface") + _eglDestroyContext = libEGL.NewProc("eglDestroyContext") + _eglDestroySurface = libEGL.NewProc("eglDestroySurface") + _eglGetConfigAttrib = libEGL.NewProc("eglGetConfigAttrib") + _eglGetDisplay = libEGL.NewProc("eglGetDisplay") + _eglGetError = libEGL.NewProc("eglGetError") + _eglInitialize = libEGL.NewProc("eglInitialize") + _eglMakeCurrent = libEGL.NewProc("eglMakeCurrent") + _eglReleaseThread = libEGL.NewProc("eglReleaseThread") + _eglSwapInterval = libEGL.NewProc("eglSwapInterval") + _eglSwapBuffers = libEGL.NewProc("eglSwapBuffers") + _eglTerminate = libEGL.NewProc("eglTerminate") + _eglQueryString = libEGL.NewProc("eglQueryString") + _eglWaitClient = libEGL.NewProc("eglWaitClient") +) + +var loadOnce sync.Once + +func loadEGL() error { + var err error + loadOnce.Do(func() { + err = loadDLLs() + }) + return err +} + +func loadDLLs() error { + if err := loadDLL(libEGL, "libEGL.dll"); err != nil { + return err + } + if err := loadDLL(gl.LibGLESv2, "libGLESv2.dll"); err != nil { + return err + } + // d3dcompiler_47.dll is needed internally for shader compilation to function. + return loadDLL(syscall.NewLazyDLL("d3dcompiler_47.dll"), "d3dcompiler_47.dll") +} + +func loadDLL(dll *syscall.LazyDLL, name string) error { + err := dll.Load() + if err != nil { + return fmt.Errorf("egl: failed to load %s: %v", name, err) + } + return nil +} + +func eglChooseConfig(disp _EGLDisplay, attribs []_EGLint) (_EGLConfig, bool) { + var cfg _EGLConfig + var ncfg _EGLint + a := &attribs[0] + r, _, _ := _eglChooseConfig.Call(uintptr(disp), uintptr(unsafe.Pointer(a)), uintptr(unsafe.Pointer(&cfg)), 1, uintptr(unsafe.Pointer(&ncfg))) + issue34474KeepAlive(a) + return cfg, r != 0 +} + +func eglCreateContext(disp _EGLDisplay, cfg _EGLConfig, shareCtx _EGLContext, attribs []_EGLint) _EGLContext { + a := &attribs[0] + c, _, _ := _eglCreateContext.Call(uintptr(disp), uintptr(cfg), uintptr(shareCtx), uintptr(unsafe.Pointer(a))) + issue34474KeepAlive(a) + return _EGLContext(c) +} + +func eglCreateWindowSurface(disp _EGLDisplay, cfg _EGLConfig, win NativeWindowType, attribs []_EGLint) _EGLSurface { + a := &attribs[0] + s, _, _ := _eglCreateWindowSurface.Call(uintptr(disp), uintptr(cfg), uintptr(win), uintptr(unsafe.Pointer(a))) + issue34474KeepAlive(a) + return _EGLSurface(s) +} + +func eglDestroySurface(disp _EGLDisplay, surf _EGLSurface) bool { + r, _, _ := _eglDestroySurface.Call(uintptr(disp), uintptr(surf)) + return r != 0 +} + +func eglDestroyContext(disp _EGLDisplay, ctx _EGLContext) bool { + r, _, _ := _eglDestroyContext.Call(uintptr(disp), uintptr(ctx)) + return r != 0 +} + +func eglGetConfigAttrib(disp _EGLDisplay, cfg _EGLConfig, attr _EGLint) (_EGLint, bool) { + var val uintptr + r, _, _ := _eglGetConfigAttrib.Call(uintptr(disp), uintptr(cfg), uintptr(attr), uintptr(unsafe.Pointer(&val))) + return _EGLint(val), r != 0 +} + +func eglGetDisplay(disp NativeDisplayType) _EGLDisplay { + d, _, _ := _eglGetDisplay.Call(uintptr(disp)) + return _EGLDisplay(d) +} + +func eglGetError() _EGLint { + e, _, _ := _eglGetError.Call() + return _EGLint(e) +} + +func eglInitialize(disp _EGLDisplay) (_EGLint, _EGLint, bool) { + var maj, min uintptr + r, _, _ := _eglInitialize.Call(uintptr(disp), uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min))) + return _EGLint(maj), _EGLint(min), r != 0 +} + +func eglMakeCurrent(disp _EGLDisplay, draw, read _EGLSurface, ctx _EGLContext) bool { + r, _, _ := _eglMakeCurrent.Call(uintptr(disp), uintptr(draw), uintptr(read), uintptr(ctx)) + return r != 0 +} + +func eglReleaseThread() bool { + r, _, _ := _eglReleaseThread.Call() + return r != 0 +} + +func eglSwapInterval(disp _EGLDisplay, interval _EGLint) bool { + r, _, _ := _eglSwapInterval.Call(uintptr(disp), uintptr(interval)) + return r != 0 +} + +func eglSwapBuffers(disp _EGLDisplay, surf _EGLSurface) bool { + r, _, _ := _eglSwapBuffers.Call(uintptr(disp), uintptr(surf)) + return r != 0 +} + +func eglTerminate(disp _EGLDisplay) bool { + r, _, _ := _eglTerminate.Call(uintptr(disp)) + return r != 0 +} + +func eglQueryString(disp _EGLDisplay, name _EGLint) string { + r, _, _ := _eglQueryString.Call(uintptr(disp), uintptr(name)) + return syscall.BytePtrToString((*byte)(unsafe.Pointer(r))) +} + +func eglWaitClient() bool { + r, _, _ := _eglWaitClient.Call() + return r != 0 +} + +// issue34474KeepAlive calls runtime.KeepAlive as a +// workaround for golang.org/issue/34474. +func issue34474KeepAlive(v interface{}) { + runtime.KeepAlive(v) +} |