aboutsummaryrefslogtreecommitdiff
path: root/vendor/gioui.org/app/metal_darwin.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gioui.org/app/metal_darwin.go')
-rw-r--r--vendor/gioui.org/app/metal_darwin.go172
1 files changed, 172 insertions, 0 deletions
diff --git a/vendor/gioui.org/app/metal_darwin.go b/vendor/gioui.org/app/metal_darwin.go
new file mode 100644
index 0000000..06b89f3
--- /dev/null
+++ b/vendor/gioui.org/app/metal_darwin.go
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: Unlicense OR MIT
+
+//go:build !nometal
+// +build !nometal
+
+package app
+
+import (
+ "errors"
+
+ "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;
+ }
+ }
+}
+
+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];
+ }
+}
+
+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, error) {
+ if c.drawable != 0 || c.texture != 0 {
+ return nil, errors.New("metal:a previous RenderTarget wasn't Presented")
+ }
+ c.drawable = C.nextDrawable(c.layer)
+ if c.drawable == 0 {
+ return nil, errors.New("metal: [CAMetalLayer nextDrawable] failed")
+ }
+ c.texture = C.drawableTexture(c.drawable)
+ if c.texture == 0 {
+ return nil, errors.New("metal: CADrawable.texture is nil")
+ }
+ return gpu.MetalRenderTarget{
+ Texture: uintptr(c.texture),
+ }, nil
+}
+
+func (c *mtlContext) API() gpu.API {
+ return gpu.Metal{
+ Device: uintptr(c.dev),
+ Queue: uintptr(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)
+}