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:
Elias Naur
2021-08-03 16:53:42 +02:00
parent a7f08eedf3
commit 3b2992c37e
21 changed files with 1603 additions and 151 deletions
+14 -10
View File
@@ -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
+5 -1
View File
@@ -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;
+2 -2
View File
@@ -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
+7 -1
View File
@@ -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[] = {
+178
View File
@@ -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)
}
+48
View File
@@ -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)
}
+49
View File
@@ -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)
}
+6 -39
View File
@@ -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) {
+5 -3
View File
@@ -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);
}
+1 -3
View File
@@ -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
+15 -1
View File
@@ -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);
}
}
+1 -1
View File
@@ -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
)
+2 -2
View File
@@ -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=
+6
View File
@@ -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
View File
@@ -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]
+44 -21
View File
@@ -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{}
}
-25
View File
@@ -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];
}
-41
View File
@@ -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]);
}
+21
View File
@@ -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() {}
+5
View File
@@ -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