mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
gpu,app/internal/wm: add Metal port
The OpenGL (ES) implementations on Apple platforms are deprecated and don't support GPU compute programs. This change adds support for the replacement, the Metal GPU API. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+14
-10
@@ -1,11 +1,13 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
//go:build darwin && ios
|
||||
// +build darwin,ios
|
||||
//go:build darwin && ios && nometal
|
||||
// +build darwin,ios,nometal
|
||||
|
||||
package wm
|
||||
|
||||
/*
|
||||
@import UIKit;
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
@@ -15,6 +17,14 @@ __attribute__ ((visibility ("hidden"))) int gio_presentRenderbuffer(CFTypeRef ct
|
||||
__attribute__ ((visibility ("hidden"))) int gio_makeCurrent(CFTypeRef ctx);
|
||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createContext(void);
|
||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLLayer(void);
|
||||
|
||||
static CFTypeRef getViewLayer(CFTypeRef viewRef) {
|
||||
@autoreleasepool {
|
||||
UIView *view = (__bridge UIView *)viewRef;
|
||||
return CFBridgingRetain(view.layer);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -36,12 +46,6 @@ type context struct {
|
||||
colorBuffer gl.Renderbuffer
|
||||
}
|
||||
|
||||
func init() {
|
||||
layerFactory = func() uintptr {
|
||||
return uintptr(C.gio_createGLLayer())
|
||||
}
|
||||
}
|
||||
|
||||
func newContext(w *window) (*context, error) {
|
||||
ctx := C.gio_createContext()
|
||||
if ctx == 0 {
|
||||
@@ -55,7 +59,7 @@ func newContext(w *window) (*context, error) {
|
||||
c := &context{
|
||||
ctx: ctx,
|
||||
owner: w,
|
||||
layer: C.CFTypeRef(w.contextLayer()),
|
||||
layer: C.getViewLayer(w.contextView()),
|
||||
c: f,
|
||||
}
|
||||
return c, nil
|
||||
@@ -116,7 +120,7 @@ func (c *context) Refresh() error {
|
||||
c.frameBuffer = c.c.CreateFramebuffer()
|
||||
c.colorBuffer = c.c.CreateRenderbuffer()
|
||||
}
|
||||
if !c.owner.isVisible() {
|
||||
if !c.owner.visible {
|
||||
// Make sure any in-flight GL commands are complete.
|
||||
c.c.Finish()
|
||||
return nil
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// +build darwin,ios
|
||||
// +build darwin,ios,nometal
|
||||
|
||||
@import UIKit;
|
||||
@import OpenGLES;
|
||||
|
||||
#include "_cgo_export.h"
|
||||
|
||||
Class gio_layerClass(void) {
|
||||
return [CAEAGLLayer class];
|
||||
}
|
||||
|
||||
int gio_renderbufferStorage(CFTypeRef ctxRef, CFTypeRef layerRef, GLenum buffer) {
|
||||
EAGLContext *ctx = (__bridge EAGLContext *)ctxRef;
|
||||
CAEAGLLayer *layer = (__bridge CAEAGLLayer *)layerRef;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
//go:build darwin && !ios
|
||||
// +build darwin,!ios
|
||||
//go:build darwin && !ios && nometal
|
||||
// +build darwin,!ios,nometal
|
||||
|
||||
package wm
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// +build darwin,!ios
|
||||
// +build darwin,!ios,nometal
|
||||
|
||||
@import AppKit;
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include "_cgo_export.h"
|
||||
|
||||
CALayer *gio_layerFactory(void) {
|
||||
@autoreleasepool {
|
||||
return [CALayer layer];
|
||||
}
|
||||
}
|
||||
|
||||
CFTypeRef gio_createGLContext(void) {
|
||||
@autoreleasepool {
|
||||
NSOpenGLPixelFormatAttribute attr[] = {
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
//go:build !nometal
|
||||
// +build !nometal
|
||||
|
||||
package wm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"gioui.org/gpu"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc
|
||||
|
||||
@import Metal;
|
||||
@import QuartzCore.CAMetalLayer;
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
static CFTypeRef createMetalDevice(void) {
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = MTLCreateSystemDefaultDevice();
|
||||
return CFBridgingRetain(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void setupLayer(CFTypeRef layerRef, CFTypeRef devRef) {
|
||||
@autoreleasepool {
|
||||
CAMetalLayer *layer = (__bridge CAMetalLayer *)layerRef;
|
||||
id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
|
||||
layer.device = dev;
|
||||
// Package gpu assumes an sRGB-encoded framebuffer.
|
||||
layer.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
// Never let nextDrawable time out and return nil.
|
||||
layer.allowsNextDrawableTimeout = NO;
|
||||
}
|
||||
if (@available(iOS 11.2, *)) {
|
||||
// Minimize latency from input to window and save a bit of memory.
|
||||
layer.maximumDrawableCount = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CFTypeRef nextDrawable(CFTypeRef layerRef) {
|
||||
@autoreleasepool {
|
||||
CAMetalLayer *layer = (__bridge CAMetalLayer *)layerRef;
|
||||
return CFBridgingRetain([layer nextDrawable]);
|
||||
}
|
||||
}
|
||||
|
||||
static CFTypeRef drawableTexture(CFTypeRef drawableRef) {
|
||||
@autoreleasepool {
|
||||
id<CAMetalDrawable> drawable = (__bridge id<CAMetalDrawable>)drawableRef;
|
||||
return CFBridgingRetain(drawable.texture);
|
||||
}
|
||||
}
|
||||
|
||||
static void presentDrawable(CFTypeRef queueRef, CFTypeRef drawableRef) {
|
||||
@autoreleasepool {
|
||||
id<MTLDrawable> drawable = (__bridge id<MTLDrawable>)drawableRef;
|
||||
id<MTLCommandQueue> queue = (__bridge id<MTLCommandQueue>)queueRef;
|
||||
id<MTLCommandBuffer> cmdBuffer = [queue commandBuffer];
|
||||
[cmdBuffer presentDrawable:drawable];
|
||||
[cmdBuffer commit];
|
||||
[cmdBuffer waitUntilCompleted];
|
||||
}
|
||||
}
|
||||
|
||||
static CFTypeRef newCommandQueue(CFTypeRef devRef) {
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
|
||||
return CFBridgingRetain([dev newCommandQueue]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type mtlContext struct {
|
||||
dev C.CFTypeRef
|
||||
view C.CFTypeRef
|
||||
layer C.CFTypeRef
|
||||
queue C.CFTypeRef
|
||||
drawable C.CFTypeRef
|
||||
texture C.CFTypeRef
|
||||
}
|
||||
|
||||
func newMtlContext(w *window) (*mtlContext, error) {
|
||||
dev := C.createMetalDevice()
|
||||
if dev == 0 {
|
||||
return nil, errors.New("metal: MTLCreateSystemDefaultDevice failed")
|
||||
}
|
||||
view := w.contextView()
|
||||
layer := getMetalLayer(view)
|
||||
if layer == 0 {
|
||||
C.CFRelease(dev)
|
||||
return nil, errors.New("metal: CAMetalLayer construction failed")
|
||||
}
|
||||
queue := C.newCommandQueue(dev)
|
||||
if layer == 0 {
|
||||
C.CFRelease(dev)
|
||||
C.CFRelease(layer)
|
||||
return nil, errors.New("metal: [MTLDevice newCommandQueue] failed")
|
||||
}
|
||||
C.setupLayer(layer, dev)
|
||||
c := &mtlContext{
|
||||
dev: dev,
|
||||
view: view,
|
||||
layer: layer,
|
||||
queue: queue,
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *mtlContext) RenderTarget() gpu.RenderTarget {
|
||||
if c.drawable != 0 || c.texture != 0 {
|
||||
panic("a previous RenderTarget wasn't Presented")
|
||||
}
|
||||
c.drawable = C.nextDrawable(c.layer)
|
||||
if c.drawable == 0 {
|
||||
panic("metal: [CAMetalLayer nextDrawable] failed")
|
||||
}
|
||||
c.texture = C.drawableTexture(c.drawable)
|
||||
if c.texture == 0 {
|
||||
panic("metal: CADrawable.texture is nil")
|
||||
}
|
||||
return gpu.MetalRenderTarget{
|
||||
Texture: unsafe.Pointer(c.texture),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *mtlContext) API() gpu.API {
|
||||
return gpu.Metal{
|
||||
Device: unsafe.Pointer(c.dev),
|
||||
Queue: unsafe.Pointer(c.queue),
|
||||
PixelFormat: int(C.MTLPixelFormatBGRA8Unorm_sRGB),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *mtlContext) Release() {
|
||||
C.CFRelease(c.queue)
|
||||
C.CFRelease(c.dev)
|
||||
C.CFRelease(c.layer)
|
||||
if c.drawable != 0 {
|
||||
C.CFRelease(c.drawable)
|
||||
}
|
||||
if c.texture != 0 {
|
||||
C.CFRelease(c.texture)
|
||||
}
|
||||
*c = mtlContext{}
|
||||
}
|
||||
|
||||
func (c *mtlContext) Present() error {
|
||||
C.CFRelease(c.texture)
|
||||
c.texture = 0
|
||||
C.presentDrawable(c.queue, c.drawable)
|
||||
C.CFRelease(c.drawable)
|
||||
c.drawable = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *mtlContext) Lock() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *mtlContext) Unlock() {}
|
||||
|
||||
func (c *mtlContext) Refresh() error {
|
||||
resizeDrawable(c.view, c.layer)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *window) NewContext() (Context, error) {
|
||||
return newMtlContext(w)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
//go:build !nometal
|
||||
// +build !nometal
|
||||
|
||||
package wm
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc
|
||||
|
||||
@import UIKit;
|
||||
|
||||
@import QuartzCore.CAMetalLayer;
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
Class gio_layerClass(void) {
|
||||
return [CAMetalLayer class];
|
||||
}
|
||||
|
||||
static CFTypeRef getMetalLayer(CFTypeRef viewRef) {
|
||||
@autoreleasepool {
|
||||
UIView *view = (__bridge UIView *)viewRef;
|
||||
return CFBridgingRetain(view.layer);
|
||||
}
|
||||
}
|
||||
|
||||
static void resizeDrawable(CFTypeRef viewRef, CFTypeRef layerRef) {
|
||||
@autoreleasepool {
|
||||
UIView *view = (__bridge UIView *)viewRef;
|
||||
CAMetalLayer *layer = (__bridge CAMetalLayer *)layerRef;
|
||||
layer.contentsScale = view.contentScaleFactor;
|
||||
CGSize size = layer.bounds.size;
|
||||
size.width *= layer.contentsScale;
|
||||
size.height *= layer.contentsScale;
|
||||
layer.drawableSize = size;
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func getMetalLayer(view C.CFTypeRef) C.CFTypeRef {
|
||||
return C.getMetalLayer(view)
|
||||
}
|
||||
|
||||
func resizeDrawable(view, layer C.CFTypeRef) {
|
||||
C.resizeDrawable(view, layer)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
//go:build darwin && !ios && !nometal
|
||||
// +build darwin,!ios,!nometal
|
||||
|
||||
package wm
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc
|
||||
|
||||
@import AppKit;
|
||||
|
||||
@import QuartzCore.CAMetalLayer;
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
CALayer *gio_layerFactory(void) {
|
||||
@autoreleasepool {
|
||||
return [CAMetalLayer layer];
|
||||
}
|
||||
}
|
||||
|
||||
static CFTypeRef getMetalLayer(CFTypeRef viewRef) {
|
||||
@autoreleasepool {
|
||||
NSView *view = (__bridge NSView *)viewRef;
|
||||
return CFBridgingRetain(view.layer);
|
||||
}
|
||||
}
|
||||
|
||||
static void resizeDrawable(CFTypeRef viewRef, CFTypeRef layerRef) {
|
||||
@autoreleasepool {
|
||||
NSView *view = (__bridge NSView *)viewRef;
|
||||
CAMetalLayer *layer = (__bridge CAMetalLayer *)layerRef;
|
||||
CGSize size = layer.bounds.size;
|
||||
size.width *= layer.contentsScale;
|
||||
size.height *= layer.contentsScale;
|
||||
layer.drawableSize = size;
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func getMetalLayer(view C.CFTypeRef) C.CFTypeRef {
|
||||
return C.getMetalLayer(view)
|
||||
}
|
||||
|
||||
func resizeDrawable(view, layer C.CFTypeRef) {
|
||||
C.resizeDrawable(view, layer)
|
||||
}
|
||||
@@ -46,24 +46,6 @@ static void hideTextInput(CFTypeRef viewRef) {
|
||||
[view resignFirstResponder];
|
||||
}
|
||||
|
||||
static void addLayerToView(CFTypeRef viewRef, CFTypeRef layerRef) {
|
||||
UIView *view = (__bridge UIView *)viewRef;
|
||||
CALayer *layer = (__bridge CALayer *)layerRef;
|
||||
[view.layer addSublayer:layer];
|
||||
}
|
||||
|
||||
static void updateView(CFTypeRef viewRef, CFTypeRef layerRef) {
|
||||
UIView *view = (__bridge UIView *)viewRef;
|
||||
CAEAGLLayer *layer = (__bridge CAEAGLLayer *)layerRef;
|
||||
layer.contentsScale = view.contentScaleFactor;
|
||||
layer.bounds = view.bounds;
|
||||
}
|
||||
|
||||
static void removeLayer(CFTypeRef layerRef) {
|
||||
CALayer *layer = (__bridge CALayer *)layerRef;
|
||||
[layer removeFromSuperlayer];
|
||||
}
|
||||
|
||||
static struct drawParams viewDrawParams(CFTypeRef viewRef) {
|
||||
UIView *v = (__bridge UIView *)viewRef;
|
||||
struct drawParams params;
|
||||
@@ -92,7 +74,6 @@ import (
|
||||
"image"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
@@ -112,8 +93,7 @@ type window struct {
|
||||
w Callbacks
|
||||
displayLink *displayLink
|
||||
|
||||
layer C.CFTypeRef
|
||||
visible atomic.Value
|
||||
visible bool
|
||||
cursor pointer.CursorName
|
||||
|
||||
pointerMap []C.CFTypeRef
|
||||
@@ -121,8 +101,6 @@ type window struct {
|
||||
|
||||
var mainWindow = newWindowRendezvous()
|
||||
|
||||
var layerFactory func() uintptr
|
||||
|
||||
var views = make(map[C.CFTypeRef]*window)
|
||||
|
||||
func init() {
|
||||
@@ -145,9 +123,6 @@ func onCreate(view C.CFTypeRef) {
|
||||
wopts := <-mainWindow.out
|
||||
w.w = wopts.window
|
||||
w.w.SetDriver(w)
|
||||
w.visible.Store(false)
|
||||
w.layer = C.CFTypeRef(layerFactory())
|
||||
C.addLayerToView(view, w.layer)
|
||||
views[view] = w
|
||||
w.w.Event(system.StageEvent{Stage: system.StagePaused})
|
||||
}
|
||||
@@ -163,9 +138,8 @@ func (w *window) draw(sync bool) {
|
||||
if params.width == 0 || params.height == 0 {
|
||||
return
|
||||
}
|
||||
wasVisible := w.isVisible()
|
||||
w.visible.Store(true)
|
||||
C.updateView(w.view, w.layer)
|
||||
wasVisible := w.visible
|
||||
w.visible = true
|
||||
if !wasVisible {
|
||||
w.w.Event(system.StageEvent{Stage: system.StageRunning})
|
||||
}
|
||||
@@ -195,7 +169,7 @@ func (w *window) draw(sync bool) {
|
||||
//export onStop
|
||||
func onStop(view C.CFTypeRef) {
|
||||
w := views[view]
|
||||
w.visible.Store(false)
|
||||
w.visible = false
|
||||
w.w.Event(system.StageEvent{Stage: system.StagePaused})
|
||||
}
|
||||
|
||||
@@ -205,9 +179,6 @@ func onDestroy(view C.CFTypeRef) {
|
||||
delete(views, view)
|
||||
w.w.Event(system.DestroyEvent{})
|
||||
w.displayLink.Close()
|
||||
C.removeLayer(w.layer)
|
||||
C.CFRelease(w.layer)
|
||||
w.layer = 0
|
||||
w.view = 0
|
||||
}
|
||||
|
||||
@@ -341,12 +312,8 @@ func (w *window) lookupTouch(last bool, touch C.CFTypeRef) pointer.ID {
|
||||
return pointer.ID(id)
|
||||
}
|
||||
|
||||
func (w *window) contextLayer() uintptr {
|
||||
return uintptr(w.layer)
|
||||
}
|
||||
|
||||
func (w *window) isVisible() bool {
|
||||
return w.visible.Load().(bool)
|
||||
func (w *window) contextView() C.CFTypeRef {
|
||||
return w.view
|
||||
}
|
||||
|
||||
func (w *window) ShowTextInput(show bool) {
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "_cgo_export.h"
|
||||
#include "framework_ios.h"
|
||||
|
||||
__attribute__ ((visibility ("hidden"))) Class gio_layerClass(void);
|
||||
|
||||
@interface GioView: UIView <UIKeyInput>
|
||||
@end
|
||||
|
||||
@@ -125,6 +127,9 @@ NSArray<UIKeyCommand *> *_keyCommands;
|
||||
gio_onFrameCallback((__bridge CFTypeRef)link);
|
||||
}
|
||||
|
||||
+ (Class)layerClass {
|
||||
return gio_layerClass();
|
||||
}
|
||||
- (void)willMoveToWindow:(UIWindow *)newWindow {
|
||||
if (self.window != nil) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
@@ -157,9 +162,6 @@ NSArray<UIKeyCommand *> *_keyCommands;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
}
|
||||
|
||||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
||||
handleTouches(0, self, touches, event);
|
||||
}
|
||||
|
||||
@@ -423,11 +423,9 @@ func gio_onClose(view C.CFTypeRef) {
|
||||
deleteView(view)
|
||||
w.w.Event(system.DestroyEvent{})
|
||||
w.displayLink.Close()
|
||||
w.displayLink = nil
|
||||
C.CFRelease(w.view)
|
||||
w.view = 0
|
||||
C.CFRelease(w.window)
|
||||
w.window = 0
|
||||
*w = window{}
|
||||
}
|
||||
|
||||
//export gio_onHide
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "_cgo_export.h"
|
||||
|
||||
__attribute__ ((visibility ("hidden"))) CALayer *gio_layerFactory(void);
|
||||
|
||||
@interface GioAppDelegate : NSObject<NSApplicationDelegate>
|
||||
@end
|
||||
|
||||
@@ -54,13 +56,24 @@ static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFlo
|
||||
gio_onMouse((__bridge CFTypeRef)view, typ, [NSEvent pressedMouseButtons], p.x, height - p.y, dx, dy, [event timestamp], [event modifierFlags]);
|
||||
}
|
||||
|
||||
@interface GioView : NSView
|
||||
@interface GioView : NSView <CALayerDelegate>
|
||||
@end
|
||||
|
||||
@implementation GioView
|
||||
// drawRect is called when OpenGL is used, displayLayer otherwise.
|
||||
// Don't know why.
|
||||
- (void)drawRect:(NSRect)r {
|
||||
gio_onDraw((__bridge CFTypeRef)self);
|
||||
}
|
||||
- (void)displayLayer:(CALayer *)layer {
|
||||
layer.contentsScale = self.window.backingScaleFactor;
|
||||
gio_onDraw((__bridge CFTypeRef)self);
|
||||
}
|
||||
- (CALayer *)makeBackingLayer {
|
||||
CALayer *layer = gio_layerFactory();
|
||||
layer.delegate = self;
|
||||
return layer;
|
||||
}
|
||||
- (void)mouseDown:(NSEvent *)event {
|
||||
handleMouse(self, event, MOUSE_DOWN, 0, 0);
|
||||
}
|
||||
@@ -221,6 +234,7 @@ CFTypeRef gio_createView(void) {
|
||||
NSRect frame = NSMakeRect(0, 0, 0, 0);
|
||||
GioView* view = [[GioView alloc] initWithFrame:frame];
|
||||
[view setWantsLayer:YES];
|
||||
view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
|
||||
return CFBridgingRetain(view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,5 +10,5 @@ require (
|
||||
|
||||
require (
|
||||
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2
|
||||
gioui.org/shader v0.0.0-20210820085839-484f7c0305de
|
||||
gioui.org/shader v0.0.0-20210821062758-133bba6632c7
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7
|
||||
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
||||
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
|
||||
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
||||
gioui.org/shader v0.0.0-20210820085839-484f7c0305de h1:fkcZh0i9T0SzMlqiDm2GBVqXZsbX6bevHcJHfR0llcg=
|
||||
gioui.org/shader v0.0.0-20210820085839-484f7c0305de/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
||||
gioui.org/shader v0.0.0-20210821062758-133bba6632c7 h1:DzpPjbWzoI5cg+WBXWSF2007lzdViHKYZR5NUOKD55k=
|
||||
gioui.org/shader v0.0.0-20210821062758-133bba6632c7/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
|
||||
@@ -17,8 +17,14 @@ type OpenGLRenderTarget = driver.OpenGLRenderTarget
|
||||
// Direct3D11RenderTarget is a render target suitable for the Direct3D 11 backend.
|
||||
type Direct3D11RenderTarget = driver.Direct3D11RenderTarget
|
||||
|
||||
// MetalRenderTarget is a render target suitable for the Metal backend.
|
||||
type MetalRenderTarget = driver.MetalRenderTarget
|
||||
|
||||
// OpenGL denotes the OpenGL or OpenGL ES API.
|
||||
type OpenGL = driver.OpenGL
|
||||
|
||||
// Direct3D11 denotes the Direct3D API.
|
||||
type Direct3D11 = driver.Direct3D11
|
||||
|
||||
// Metal denotes the Apple Metal API.
|
||||
type Metal = driver.Metal
|
||||
|
||||
+2
-1
@@ -36,6 +36,7 @@ import (
|
||||
|
||||
// Register backends.
|
||||
_ "gioui.org/gpu/internal/d3d11"
|
||||
_ "gioui.org/gpu/internal/metal"
|
||||
_ "gioui.org/gpu/internal/opengl"
|
||||
)
|
||||
|
||||
@@ -135,7 +136,7 @@ type imageOp struct {
|
||||
|
||||
// shaderModuleVersion is the exact version of gioui.org/shader expected by
|
||||
// this package. Shader programs are not backwards or forwards compatible.
|
||||
const shaderModuleVersion = "v0.0.0-20210820085839-484f7c0305de"
|
||||
const shaderModuleVersion = "v0.0.0-20210821062758-133bba6632c7"
|
||||
|
||||
func decodeStrokeOp(data []byte) clip.StrokeStyle {
|
||||
_ = data[4]
|
||||
|
||||
@@ -3,46 +3,69 @@
|
||||
package headless
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"gioui.org/gpu"
|
||||
_ "gioui.org/internal/cocoainit"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DGL_SILENCE_DEPRECATION -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c
|
||||
#cgo CFLAGS: -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c
|
||||
#cgo LDFLAGS: -framework CoreGraphics
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
@import Metal;
|
||||
|
||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_headless_newContext(void);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_headless_clearCurrentContext(CFTypeRef ctxRef);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_headless_makeCurrentContext(CFTypeRef ctxRef);
|
||||
static CFTypeRef createDevice(void) {
|
||||
@autoreleasepool {
|
||||
id dev = MTLCreateSystemDefaultDevice();
|
||||
return CFBridgingRetain(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static CFTypeRef newCommandQueue(CFTypeRef devRef) {
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
|
||||
return CFBridgingRetain([dev newCommandQueue]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type nsContext struct {
|
||||
ctx C.CFTypeRef
|
||||
type mtlContext struct {
|
||||
dev C.CFTypeRef
|
||||
queue C.CFTypeRef
|
||||
}
|
||||
|
||||
func newContext() (context, error) {
|
||||
ctx := C.gio_headless_newContext()
|
||||
return &nsContext{ctx: ctx}, nil
|
||||
dev := C.createDevice()
|
||||
if dev == 0 {
|
||||
return nil, errors.New("headless: failed to create Metal device")
|
||||
}
|
||||
queue := C.newCommandQueue(dev)
|
||||
if queue == 0 {
|
||||
C.CFRelease(dev)
|
||||
return nil, errors.New("headless: failed to create MTLQueue")
|
||||
}
|
||||
return &mtlContext{dev: dev, queue: queue}, nil
|
||||
}
|
||||
|
||||
func (c *nsContext) API() gpu.API {
|
||||
return gpu.OpenGL{}
|
||||
func (c *mtlContext) API() gpu.API {
|
||||
return gpu.Metal{
|
||||
Device: unsafe.Pointer(c.dev),
|
||||
Queue: unsafe.Pointer(c.queue),
|
||||
PixelFormat: int(C.MTLPixelFormatRGBA8Unorm_sRGB),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *nsContext) MakeCurrent() error {
|
||||
C.gio_headless_makeCurrentContext(c.ctx)
|
||||
func (c *mtlContext) MakeCurrent() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *nsContext) ReleaseCurrent() {
|
||||
C.gio_headless_clearCurrentContext(c.ctx)
|
||||
}
|
||||
func (c *mtlContext) ReleaseCurrent() {}
|
||||
|
||||
func (d *nsContext) Release() {
|
||||
if d.ctx != 0 {
|
||||
C.CFRelease(d.ctx)
|
||||
d.ctx = 0
|
||||
}
|
||||
func (d *mtlContext) Release() {
|
||||
C.CFRelease(d.dev)
|
||||
C.CFRelease(d.queue)
|
||||
*d = mtlContext{}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// +build darwin,ios
|
||||
|
||||
@import OpenGLES;
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "_cgo_export.h"
|
||||
|
||||
CFTypeRef gio_headless_newContext(void) {
|
||||
EAGLContext *ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
|
||||
if (ctx == nil) {
|
||||
return nil;
|
||||
}
|
||||
return CFBridgingRetain(ctx);
|
||||
}
|
||||
|
||||
void gio_headless_clearCurrentContext(CFTypeRef ctxRef) {
|
||||
[EAGLContext setCurrentContext:nil];
|
||||
}
|
||||
|
||||
void gio_headless_makeCurrentContext(CFTypeRef ctxRef) {
|
||||
EAGLContext *ctx = (__bridge EAGLContext *)ctxRef;
|
||||
[EAGLContext setCurrentContext:ctx];
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// +build darwin,!ios
|
||||
|
||||
@import AppKit;
|
||||
@import OpenGL;
|
||||
@import OpenGL.GL;
|
||||
@import OpenGL.GL3;
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "_cgo_export.h"
|
||||
|
||||
CFTypeRef gio_headless_newContext(void) {
|
||||
NSOpenGLPixelFormatAttribute attr[] = {
|
||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
||||
NSOpenGLPFAColorSize, 24,
|
||||
NSOpenGLPFAAccelerated,
|
||||
// Opt-in to automatic GPU switching. CGL-only property.
|
||||
kCGLPFASupportsAutomaticGraphicsSwitching,
|
||||
NSOpenGLPFAAllowOfflineRenderers,
|
||||
0
|
||||
};
|
||||
NSOpenGLPixelFormat *pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
|
||||
if (pixFormat == nil) {
|
||||
return NULL;
|
||||
}
|
||||
NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:pixFormat shareContext:nil];
|
||||
return CFBridgingRetain(ctx);
|
||||
}
|
||||
|
||||
void gio_headless_clearCurrentContext(CFTypeRef ctxRef) {
|
||||
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
|
||||
CGLUnlockContext([ctx CGLContextObj]);
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
}
|
||||
|
||||
void gio_headless_makeCurrentContext(CFTypeRef ctxRef) {
|
||||
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
|
||||
[ctx makeCurrentContext];
|
||||
CGLLockContext([ctx CGLContextObj]);
|
||||
}
|
||||
@@ -26,6 +26,11 @@ type Direct3D11RenderTarget struct {
|
||||
RenderTarget unsafe.Pointer
|
||||
}
|
||||
|
||||
type MetalRenderTarget struct {
|
||||
// Texture is a MTLTexture.
|
||||
Texture unsafe.Pointer
|
||||
}
|
||||
|
||||
type OpenGL struct {
|
||||
// ES forces the use of ANGLE OpenGL ES libraries on macOS. It is
|
||||
// ignored on all other platforms.
|
||||
@@ -41,10 +46,20 @@ type Direct3D11 struct {
|
||||
Device unsafe.Pointer
|
||||
}
|
||||
|
||||
type Metal struct {
|
||||
// Device is an MTLDevice.
|
||||
Device unsafe.Pointer
|
||||
// Queue is a MTLCommandQueue.
|
||||
Queue unsafe.Pointer
|
||||
// PixelFormat is the MTLPixelFormat of the default framebuffer.
|
||||
PixelFormat int
|
||||
}
|
||||
|
||||
// API specific device constructors.
|
||||
var (
|
||||
NewOpenGLDevice func(api OpenGL) (Device, error)
|
||||
NewDirect3D11Device func(api Direct3D11) (Device, error)
|
||||
NewMetalDevice func(api Metal) (Device, error)
|
||||
)
|
||||
|
||||
// NewDevice creates a new Device given the api.
|
||||
@@ -62,11 +77,17 @@ func NewDevice(api API) (Device, error) {
|
||||
if NewDirect3D11Device != nil {
|
||||
return NewDirect3D11Device(api)
|
||||
}
|
||||
case Metal:
|
||||
if NewMetalDevice != nil {
|
||||
return NewMetalDevice(api)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("driver: no driver available for the API %T", api)
|
||||
}
|
||||
|
||||
func (OpenGL) implementsAPI() {}
|
||||
func (Direct3D11) implementsAPI() {}
|
||||
func (Metal) implementsAPI() {}
|
||||
func (OpenGLRenderTarget) ImplementsRenderTarget() {}
|
||||
func (Direct3D11RenderTarget) ImplementsRenderTarget() {}
|
||||
func (MetalRenderTarget) ImplementsRenderTarget() {}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// This file exists so this package builds on non-Darwin platforms.
|
||||
|
||||
package metal
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user