dmitri.shuralyov.com/gpu/mtl/...

all: add darwin/arm64 (macOS) support

The Objective-C BOOL type is defined as a signed char on on Intel-based
Mac computers, but on Apple silicon, it is defined as as a native bool.¹

This makes it hard to write portable Cgo code across darwin/amd64 and
darwin/arm64 ports. So, stop relying on it, and use the bool type from
<stdbool.h> instead.

¹ https://developer.apple.com/documentation/apple_silicon/addressing_architectural_differences_in_your_macos_code#3616879
dmitshur committed 3 years ago commit 28db891af037715d8c1deec7652485a173c60e25
Collapse all
example/movingtriangle/internal/appkit/appkit.go
@@ -13,10 +13,11 @@ import (

	"dmitri.shuralyov.com/gpu/mtl/example/movingtriangle/internal/coreanim"
)

/*
#include <stdbool.h>
#include "appkit.h"
*/
import "C"

// Window is a window that an app displays on the screen.
@@ -55,14 +56,7 @@ func (v View) SetLayer(l coreanim.Layer) {

// SetWantsLayer sets v.wantsLayer to wantsLayer.
//
// Reference: https://developer.apple.com/documentation/appkit/nsview/1483695-wantslayer.
func (v View) SetWantsLayer(wantsLayer bool) {
	C.View_SetWantsLayer(v.view, toCBool(wantsLayer))
}

func toCBool(b bool) C.BOOL {
	if b {
		return 1
	}
	return 0
	C.View_SetWantsLayer(v.view, C.bool(wantsLayer))
}
example/movingtriangle/internal/appkit/appkit.h
@@ -1,8 +1,6 @@
// +build darwin

typedef signed char BOOL;

void * Window_ContentView(void * window);

void View_SetLayer(void * view, void * layer);
void View_SetWantsLayer(void * view, BOOL wantsLayer);
void View_SetWantsLayer(void * view, bool wantsLayer);
example/movingtriangle/internal/appkit/appkit.m
@@ -9,8 +9,8 @@ void * Window_ContentView(void * window) {

void View_SetLayer(void * view, void * layer) {
	((NSView *)view).layer = (CALayer *)layer;
}

void View_SetWantsLayer(void * view, BOOL wantsLayer) {
void View_SetWantsLayer(void * view, bool wantsLayer) {
	((NSView *)view).wantsLayer = wantsLayer;
}
example/movingtriangle/internal/coreanim/coreanim.go
@@ -15,10 +15,11 @@ import (
	"dmitri.shuralyov.com/gpu/mtl"
)

/*
#cgo LDFLAGS: -framework QuartzCore -framework Foundation
#include <stdbool.h>
#include "coreanim.h"
*/
import "C"

// Layer is an object that manages image-based content and
@@ -91,11 +92,11 @@ func (ml MetalLayer) SetMaximumDrawableCount(count int) {
// SetDisplaySyncEnabled controls whether the Metal layer and its drawables
// are synchronized with the display's refresh rate.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2887087-displaysyncenabled.
func (ml MetalLayer) SetDisplaySyncEnabled(enabled bool) {
	C.MetalLayer_SetDisplaySyncEnabled(ml.metalLayer, toCBool(enabled))
	C.MetalLayer_SetDisplaySyncEnabled(ml.metalLayer, C.bool(enabled))
}

// SetDrawableSize sets the size, in pixels, of textures for rendering layer content.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478174-drawablesize.
@@ -129,12 +130,5 @@ func (md MetalDrawable) Drawable() unsafe.Pointer { return md.metalDrawable }
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable/1478159-texture.
func (md MetalDrawable) Texture() mtl.Texture {
	return mtl.NewTexture(C.MetalDrawable_Texture(md.metalDrawable))
}

func toCBool(b bool) C.BOOL {
	if b {
		return 1
	}
	return 0
}
example/movingtriangle/internal/coreanim/coreanim.h
@@ -1,17 +1,16 @@
// +build darwin

typedef signed char BOOL;
typedef unsigned long uint_t;
typedef unsigned short uint16_t;

void * MakeMetalLayer();

uint16_t     MetalLayer_PixelFormat(void * metalLayer);
void         MetalLayer_SetDevice(void * metalLayer, void * device);
const char * MetalLayer_SetPixelFormat(void * metalLayer, uint16_t pixelFormat);
const char * MetalLayer_SetMaximumDrawableCount(void * metalLayer, uint_t maximumDrawableCount);
void         MetalLayer_SetDisplaySyncEnabled(void * metalLayer, BOOL displaySyncEnabled);
void         MetalLayer_SetDisplaySyncEnabled(void * metalLayer, bool displaySyncEnabled);
void         MetalLayer_SetDrawableSize(void * metalLayer, double width, double height);
void *       MetalLayer_NextDrawable(void * metalLayer);

void * MetalDrawable_Texture(void * drawable);
example/movingtriangle/internal/coreanim/coreanim.m
@@ -35,11 +35,11 @@ const char * MetalLayer_SetMaximumDrawableCount(void * metalLayer, uint_t maximu
		}
	}
	return NULL;
}

void MetalLayer_SetDisplaySyncEnabled(void * metalLayer, BOOL displaySyncEnabled) {
void MetalLayer_SetDisplaySyncEnabled(void * metalLayer, bool displaySyncEnabled) {
	((CAMetalLayer *)metalLayer).displaySyncEnabled = displaySyncEnabled;
}

void MetalLayer_SetDrawableSize(void * metalLayer, double width, double height) {
	((CAMetalLayer *)metalLayer).drawableSize = (CGSize){width, height};
mtl.go
@@ -17,10 +17,11 @@ import (
)

/*
#cgo LDFLAGS: -framework Metal -framework CoreGraphics -framework Foundation
#include <stdlib.h>
#include <stdbool.h>
#include "mtl.h"
struct Library Go_Device_MakeLibrary(void * device, _GoString_ source) {
	return Device_MakeLibrary(device, _GoStringPtr(source), _GoStringLen(source));
}
*/
@@ -299,13 +300,13 @@ func CreateSystemDefaultDevice() (Device, error) {
		return Device{}, errors.New("Metal is not supported on this system")
	}

	return Device{
		device:     d.Device,
		Headless:   d.Headless != 0,
		LowPower:   d.LowPower != 0,
		Removable:  d.Removable != 0,
		Headless:   bool(d.Headless),
		LowPower:   bool(d.LowPower),
		Removable:  bool(d.Removable),
		RegistryID: uint64(d.RegistryID),
		Name:       C.GoString(d.Name),
	}, nil
}

@@ -319,13 +320,13 @@ func CopyAllDevices() []Device {
	ds := make([]Device, d.Length)
	for i := 0; i < len(ds); i++ {
		d := (*C.struct_Device)(unsafe.Pointer(uintptr(unsafe.Pointer(d.Devices)) + uintptr(i)*C.sizeof_struct_Device))

		ds[i].device = d.Device
		ds[i].Headless = d.Headless != 0
		ds[i].LowPower = d.LowPower != 0
		ds[i].Removable = d.Removable != 0
		ds[i].Headless = bool(d.Headless)
		ds[i].LowPower = bool(d.LowPower)
		ds[i].Removable = bool(d.Removable)
		ds[i].RegistryID = uint64(d.RegistryID)
		ds[i].Name = C.GoString(d.Name)
	}
	return ds
}
@@ -335,11 +336,11 @@ func (d Device) Device() unsafe.Pointer { return d.device }

// SupportsFeatureSet reports whether device d supports feature set fs.
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433418-supportsfeatureset.
func (d Device) SupportsFeatureSet(fs FeatureSet) bool {
	return C.Device_SupportsFeatureSet(d.device, C.uint16_t(fs)) != 0
	return bool(C.Device_SupportsFeatureSet(d.device, C.uint16_t(fs)))
}

// MakeCommandQueue creates a serial command submission queue.
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433388-makecommandqueue.
mtl.h
@@ -1,18 +1,17 @@
// +build darwin

typedef signed char BOOL;
typedef unsigned long uint_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long long uint64_t;

struct Device {
	void *       Device;
	BOOL         Headless;
	BOOL         LowPower;
	BOOL         Removable;
	bool         Headless;
	bool         LowPower;
	bool         Removable;
	uint64_t     RegistryID;
	const char * Name;
};

struct Devices {
@@ -75,11 +74,11 @@ struct Region {
};

struct Device CreateSystemDefaultDevice();
struct Devices CopyAllDevices();

BOOL                       Device_SupportsFeatureSet(void * device, uint16_t featureSet);
bool                       Device_SupportsFeatureSet(void * device, uint16_t featureSet);
void *                     Device_MakeCommandQueue(void * device);
struct Library             Device_MakeLibrary(void * device, const char * source, size_t sourceLength);
struct RenderPipelineState Device_MakeRenderPipelineState(void * device, struct RenderPipelineDescriptor descriptor);
void *                     Device_MakeBuffer(void * device, const void * bytes, size_t length, uint16_t options);
void *                     Device_MakeTexture(void * device, struct TextureDescriptor descriptor);
mtl.m
@@ -1,9 +1,8 @@
// +build darwin

#import <Metal/Metal.h>
#include <stdlib.h>
#include "mtl.h"

struct Device CreateSystemDefaultDevice() {
	id<MTLDevice> device = MTLCreateSystemDefaultDevice();
	if (!device) {
@@ -38,11 +37,11 @@ struct Devices CopyAllDevices() {
	}
	d.Length = devices.count;
	return d;
}

BOOL Device_SupportsFeatureSet(void * device, uint16_t featureSet) {
bool Device_SupportsFeatureSet(void * device, uint16_t featureSet) {
	return [(id<MTLDevice>)device supportsFeatureSet:featureSet];
}

void * Device_MakeCommandQueue(void * device) {
	return [(id<MTLDevice>)device newCommandQueue];