mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-02 16:06:19 +00:00
8611894b4b
app.Window implements a method for safely running functions against the underlying native window through the driverFuncs channel. However, the functions still run in a different goroutine than the one driving the native event loop, which forces the implementations in package wm to do complicated synchronization. A previous change added a mechanism to run functions in the native event loop thread. The macOS port needed this functionality, but with some care it can be generalized. That's what this change does through the new Run method. The advantage is that the thread switch dance is now confined to app.Window, with the help of a generic wm.Driver.Wakeup method. All other Driver methods can then assume they run on their event loop threads. Run is exported because it is also needed for programs that use Windows configured with CustomRenderer to control their own rendering. Signed-off-by: Elias Naur <mail@eliasnaur.com>
96 lines
2.1 KiB
Go
96 lines
2.1 KiB
Go
// SPDX-License-Identifier: Unlicense OR MIT
|
|
|
|
// +build darwin,!ios
|
|
|
|
package wm
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"gioui.org/gpu"
|
|
"gioui.org/internal/gl"
|
|
)
|
|
|
|
/*
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#include <CoreGraphics/CoreGraphics.h>
|
|
#include <AppKit/AppKit.h>
|
|
#include <OpenGL/gl3.h>
|
|
|
|
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLContext(void);
|
|
__attribute__ ((visibility ("hidden"))) void gio_prepareContext(void);
|
|
__attribute__ ((visibility ("hidden"))) void gio_setContextView(CFTypeRef ctx, CFTypeRef view);
|
|
__attribute__ ((visibility ("hidden"))) void gio_makeCurrentContext(CFTypeRef ctx);
|
|
__attribute__ ((visibility ("hidden"))) void gio_flushContextBuffer(CFTypeRef ctx);
|
|
__attribute__ ((visibility ("hidden"))) void gio_clearCurrentContext(void);
|
|
__attribute__ ((visibility ("hidden"))) void gio_lockContext(CFTypeRef ctxRef);
|
|
__attribute__ ((visibility ("hidden"))) void gio_unlockContext(CFTypeRef ctxRef);
|
|
*/
|
|
import "C"
|
|
|
|
type context struct {
|
|
c *gl.Functions
|
|
ctx C.CFTypeRef
|
|
view C.CFTypeRef
|
|
prepared bool
|
|
}
|
|
|
|
func newContext(w *window) (*context, error) {
|
|
view := w.contextView()
|
|
ctx := C.gio_createGLContext()
|
|
if ctx == 0 {
|
|
return nil, errors.New("gl: failed to create NSOpenGLContext")
|
|
}
|
|
// [NSOpenGLContext setView] must run on the main thread. Fortunately,
|
|
// newContext is only called during a [NSView draw] on the main thread.
|
|
w.w.Run(func() {
|
|
C.gio_setContextView(ctx, view)
|
|
})
|
|
c := &context{
|
|
ctx: ctx,
|
|
view: view,
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func (c *context) API() gpu.API {
|
|
return gpu.OpenGL{}
|
|
}
|
|
|
|
func (c *context) Release() {
|
|
if c.ctx != 0 {
|
|
C.gio_clearCurrentContext()
|
|
C.CFRelease(c.ctx)
|
|
c.ctx = 0
|
|
}
|
|
}
|
|
|
|
func (c *context) Present() error {
|
|
// Assume the caller already locked the context.
|
|
C.glFlush()
|
|
return nil
|
|
}
|
|
|
|
func (c *context) Lock() {
|
|
C.gio_lockContext(c.ctx)
|
|
}
|
|
|
|
func (c *context) Unlock() {
|
|
C.gio_unlockContext(c.ctx)
|
|
}
|
|
|
|
func (c *context) MakeCurrent() error {
|
|
c.Lock()
|
|
defer c.Unlock()
|
|
C.gio_makeCurrentContext(c.ctx)
|
|
if !c.prepared {
|
|
c.prepared = true
|
|
C.gio_prepareContext()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *window) NewContext() (Context, error) {
|
|
return newContext(w)
|
|
}
|