internal/graphicsdriver/metal: remove C for macOS (#2243)

Updates #1162
This commit is contained in:
TotallyGamerJet 2022-08-17 12:39:34 -04:00 committed by GitHub
parent fb775d806c
commit 05470f7706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 545 additions and 1105 deletions

2
go.mod
View File

@ -3,7 +3,7 @@ module github.com/hajimehoshi/ebiten/v2
go 1.15
require (
github.com/ebitengine/purego v0.0.0-20220729024107-78cdc2949de6
github.com/ebitengine/purego v0.0.0-20220816145426-8dbe340b03f1
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad
github.com/hajimehoshi/bitmapfont/v2 v2.2.1
github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41

3
go.sum
View File

@ -1,6 +1,7 @@
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ebitengine/purego v0.0.0-20220729024107-78cdc2949de6 h1:kc3Im5Yj31aW0r3VdXHk+urwClkQilDBAYYp0TXeqE8=
github.com/ebitengine/purego v0.0.0-20220729024107-78cdc2949de6/go.mod h1:Eh8I3yvknDYZeCuXH9kRNaPuHEwvXDCk378o9xszmHg=
github.com/ebitengine/purego v0.0.0-20220816145426-8dbe340b03f1 h1:kf5uxeNGrfkESJQe81OvrxJG1jZaafBjssteag0GbPQ=
github.com/ebitengine/purego v0.0.0-20220816145426-8dbe340b03f1/go.mod h1:Eh8I3yvknDYZeCuXH9kRNaPuHEwvXDCk378o9xszmHg=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad h1:kX51IjbsJPCvzV9jUoVQG9GEUqIq5hjfYzXTqQ52Rh8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/hajimehoshi/bitmapfont/v2 v2.2.1 h1:y7zcy02/UgO24IL3COqYtrRZzhRucNBtmCo/SNU648k=

View File

@ -0,0 +1,138 @@
// Copyright 2022 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cocoa
import (
"reflect"
"unsafe"
"github.com/ebitengine/purego/objc"
)
var (
class_NSInvocation = objc.GetClass("NSInvocation")
class_NSMethodSignature = objc.GetClass("NSMethodSignature")
class_NSAutoreleasePool = objc.GetClass("NSAutoreleasePool")
class_NSString = objc.GetClass("NSString")
)
var (
sel_alloc = objc.RegisterName("alloc")
sel_new = objc.RegisterName("new")
sel_release = objc.RegisterName("release")
sel_invocationWithMethodSignature = objc.RegisterName("invocationWithMethodSignature:")
sel_setSelector = objc.RegisterName("setSelector:")
sel_setTarget = objc.RegisterName("setTarget:")
sel_setArgumentAtIndex = objc.RegisterName("setArgument:atIndex:")
sel_getReturnValue = objc.RegisterName("getReturnValue:")
sel_invoke = objc.RegisterName("invoke")
sel_instanceMethodSignatureForSelector = objc.RegisterName("instanceMethodSignatureForSelector:")
sel_signatureWithObjCTypes = objc.RegisterName("signatureWithObjCTypes:")
sel_initWithUTF8String = objc.RegisterName("initWithUTF8String:")
sel_UTF8String = objc.RegisterName("UTF8String")
sel_length = objc.RegisterName("length")
)
type CGFloat float64
type CGSize struct {
Width, Height CGFloat
}
type NSError struct {
objc.ID
}
// NSInvocation is being used to call functions that can't be called directly with purego.SyscallN.
// See the downsides of that function for what it cannot do.
type NSInvocation struct {
objc.ID
}
func NSInvocation_invocationWithMethodSignature(sig NSMethodSignature) NSInvocation {
return NSInvocation{objc.ID(class_NSInvocation).Send(sel_invocationWithMethodSignature, sig.ID)}
}
func (inv NSInvocation) SetSelector(_cmd objc.SEL) {
inv.Send(sel_setSelector, _cmd)
}
func (inv NSInvocation) SetTarget(target objc.ID) {
inv.Send(sel_setTarget, target)
}
func (inv NSInvocation) SetArgumentAtIndex(arg unsafe.Pointer, idx int) {
inv.Send(sel_setArgumentAtIndex, arg, idx)
}
func (inv NSInvocation) GetReturnValue(ret unsafe.Pointer) {
inv.Send(sel_getReturnValue, ret)
}
func (inv NSInvocation) Invoke() {
inv.Send(sel_invoke)
}
type NSMethodSignature struct {
objc.ID
}
func NSMethodSignature_instanceMethodSignatureForSelector(self objc.ID, _cmd objc.SEL) NSMethodSignature {
return NSMethodSignature{self.Send(sel_instanceMethodSignatureForSelector, _cmd)}
}
// NSMethodSignature_signatureWithObjCTypes takes a string that represents the type signature of a method.
// It follows the encoding specified in the Apple Docs.
//
// [Apple Docs]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
func NSMethodSignature_signatureWithObjCTypes(types string) NSMethodSignature {
return NSMethodSignature{objc.ID(class_NSMethodSignature).Send(sel_signatureWithObjCTypes, types)}
}
type NSAutoreleasePool struct {
objc.ID
}
func NSAutoreleasePool_new() NSAutoreleasePool {
return NSAutoreleasePool{objc.ID(class_NSAutoreleasePool).Send(sel_new)}
}
func (pool NSAutoreleasePool) Release() {
pool.Send(sel_release)
}
type NSString struct {
objc.ID
}
func NSString_alloc() NSString {
return NSString{objc.ID(class_NSString).Send(sel_alloc)}
}
func (s NSString) InitWithUTF8String(utf8 string) NSString {
return NSString{s.Send(sel_initWithUTF8String, utf8)}
}
func (s NSString) String() string {
// this will be nicer with unsafe.Slice once ebitengine requires 1.17
// reflect.SliceHeader is used because it will force Go to copy the string
// into Go memory when casted to a string
var b []byte
header := (*reflect.SliceHeader)(unsafe.Pointer(&b))
header.Data = uintptr(s.Send(sel_UTF8String))
header.Len = int(s.Send(sel_length))
header.Cap = header.Len
return string(b)
}

View File

@ -1,4 +1,4 @@
// Copyright 2018 The Ebiten Authors
// Copyright 2022 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "stdint.h"
//go:build ios
// +build ios
void *Window_ContentView(uintptr_t window);
package cocoa
void View_SetLayer(void *view, void *layer);
void View_SetWantsLayer(void *view, unsigned char wantsLayer);
uint8_t View_IsInFullScreenMode(void *view);
const IsIOS = true

View File

@ -1,4 +1,4 @@
// Copyright 2018 The Ebiten Authors
// Copyright 2022 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,21 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ns_darwin.h"
#import <Cocoa/Cocoa.h>
//go:build !ios
// +build !ios
void *Window_ContentView(uintptr_t window) {
return ((NSWindow *)window).contentView;
}
package cocoa
void View_SetLayer(void *view, void *layer) {
((NSView *)view).layer = (CALayer *)layer;
}
void View_SetWantsLayer(void *view, unsigned char wantsLayer) {
((NSView *)view).wantsLayer = (BOOL)wantsLayer;
}
uint8_t View_IsInFullScreenMode(void *view) {
return ((NSView *)view).isInFullScreenMode;
}
const IsIOS = false

View File

@ -21,21 +21,16 @@ package ca
import (
"errors"
"fmt"
"unsafe"
"github.com/ebitengine/purego"
"github.com/ebitengine/purego/objc"
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
)
// Suppress the warnings about availability guard with -Wno-unguarded-availability-new.
// It is because old Xcode (8 or older?) does not accept @available syntax.
// #cgo CFLAGS: -Wno-unguarded-availability-new
// #cgo !ios CFLAGS: -mmacosx-version-min=10.12
// #cgo LDFLAGS: -framework QuartzCore -framework Foundation -framework CoreGraphics
//
// #include "ca_darwin.h"
import "C"
// Layer is an object that manages image-based content and
// allows you to perform animations on that content.
//
@ -49,40 +44,51 @@ type Layer interface {
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer.
type MetalLayer struct {
metalLayer unsafe.Pointer
metalLayer objc.ID
}
var (
coreGraphics = purego.Dlopen("/System/Library/Frameworks/CoreGraphics.framework/Versions/Current/CoreGraphics", purego.RTLD_GLOBAL)
_CGColorSpaceCreateWithName = purego.Dlsym(coreGraphics, "CGColorSpaceCreateWithName")
_CGColorSpaceRelease = purego.Dlsym(coreGraphics, "CGColorSpaceRelease")
kCGColorSpaceDisplayP3 = purego.Dlsym(coreGraphics, "kCGColorSpaceDisplayP3")
)
// MakeMetalLayer creates a new Core Animation Metal layer.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer.
func MakeMetalLayer() MetalLayer {
return MetalLayer{C.MakeMetalLayer()}
layer := objc.ID(objc.GetClass("CAMetalLayer")).Send(objc.RegisterName("new"))
if !cocoa.IsIOS {
colorspace, _, _ := purego.SyscallN(_CGColorSpaceCreateWithName, **(**uintptr)(unsafe.Pointer(&kCGColorSpaceDisplayP3))) // Dlsym returns pointer to symbol so dereference it
layer.Send(objc.RegisterName("setColorspace:"), colorspace)
purego.SyscallN(_CGColorSpaceRelease, colorspace)
}
return MetalLayer{layer}
}
// Layer implements the Layer interface.
func (ml MetalLayer) Layer() unsafe.Pointer { return ml.metalLayer }
func (ml MetalLayer) Layer() unsafe.Pointer {
return *(*unsafe.Pointer)(unsafe.Pointer(&ml.metalLayer))
}
// PixelFormat returns the pixel format of textures for rendering layer content.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat.
func (ml MetalLayer) PixelFormat() mtl.PixelFormat {
return mtl.PixelFormat(C.MetalLayer_PixelFormat(ml.metalLayer))
return mtl.PixelFormat(ml.metalLayer.Send(objc.RegisterName("pixelFormat")))
}
// SetDevice sets the Metal device responsible for the layer's drawable resources.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478163-device.
func (ml MetalLayer) SetDevice(device mtl.Device) {
C.MetalLayer_SetDevice(ml.metalLayer, device.Device())
ml.metalLayer.Send(objc.RegisterName("setDevice:"), uintptr(device.Device()))
}
// SetOpaque a Boolean value indicating whether the layer contains completely opaque content.
func (ml MetalLayer) SetOpaque(opaque bool) {
if opaque {
C.MetalLayer_SetOpaque(ml.metalLayer, 1)
} else {
C.MetalLayer_SetOpaque(ml.metalLayer, 0)
}
ml.metalLayer.Send(objc.RegisterName("setOpaque:"), opaque)
}
// SetPixelFormat controls the pixel format of textures for rendering layer content.
@ -93,10 +99,12 @@ func (ml MetalLayer) SetOpaque(opaque bool) {
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat.
func (ml MetalLayer) SetPixelFormat(pf mtl.PixelFormat) {
e := C.MetalLayer_SetPixelFormat(ml.metalLayer, C.uint16_t(pf))
if e != nil {
panic(errors.New(C.GoString(e)))
switch pf {
case mtl.PixelFormatRGBA8UNorm, mtl.PixelFormatRGBA8UNormSRGB, mtl.PixelFormatBGRA8UNorm, mtl.PixelFormatBGRA8UNormSRGB, mtl.PixelFormatStencil8:
default:
panic(errors.New(fmt.Sprintf("invalid pixel format %d", pf)))
}
ml.metalLayer.Send(objc.RegisterName("setPixelFormat:"), uint(pf))
}
// SetMaximumDrawableCount controls the number of Metal drawables in the resource pool
@ -106,10 +114,10 @@ func (ml MetalLayer) SetPixelFormat(pf mtl.PixelFormat) {
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2938720-maximumdrawablecount.
func (ml MetalLayer) SetMaximumDrawableCount(count int) {
e := C.MetalLayer_SetMaximumDrawableCount(ml.metalLayer, C.uint_t(count))
if e != nil {
panic(errors.New(C.GoString(e)))
if count < 2 || count > 3 {
panic(errors.New(fmt.Sprintf("failed trying to set maximumDrawableCount to %d outside of the valid range of [2, 3]", count)))
}
ml.metalLayer.Send(objc.RegisterName("setMaximumDrawableCount:"), count)
}
// SetDisplaySyncEnabled controls whether the Metal layer and its drawables
@ -117,30 +125,34 @@ func (ml MetalLayer) SetMaximumDrawableCount(count int) {
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2887087-displaysyncenabled.
func (ml MetalLayer) SetDisplaySyncEnabled(enabled bool) {
switch enabled {
case true:
C.MetalLayer_SetDisplaySyncEnabled(ml.metalLayer, 1)
case false:
C.MetalLayer_SetDisplaySyncEnabled(ml.metalLayer, 0)
if cocoa.IsIOS {
return
}
ml.metalLayer.Send(objc.RegisterName("setDisplaySyncEnabled:"), enabled)
}
// SetDrawableSize sets the size, in pixels, of textures for rendering layer content.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478174-drawablesize.
func (ml MetalLayer) SetDrawableSize(width, height int) {
C.MetalLayer_SetDrawableSize(ml.metalLayer, C.double(width), C.double(height))
// TODO: once objc supports calling functions with struct arguments replace this with just a ID.Send call
var sel_setDrawableSize = objc.RegisterName("setDrawableSize:")
sig := cocoa.NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(objc.GetClass("CAMetalLayer")), sel_setDrawableSize)
inv := cocoa.NSInvocation_invocationWithMethodSignature(sig)
inv.SetTarget(ml.metalLayer)
inv.SetSelector(sel_setDrawableSize)
inv.SetArgumentAtIndex(unsafe.Pointer(&cocoa.CGSize{Width: cocoa.CGFloat(width), Height: cocoa.CGFloat(height)}), 2)
inv.Invoke()
}
// NextDrawable returns a Metal drawable.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478172-nextdrawable.
func (ml MetalLayer) NextDrawable() (MetalDrawable, error) {
md := C.MetalLayer_NextDrawable(ml.metalLayer)
if md == nil {
md := ml.metalLayer.Send(objc.RegisterName("nextDrawable"))
if md == 0 {
return MetalDrawable{}, errors.New("nextDrawable returned nil")
}
return MetalDrawable{md}, nil
}
@ -148,52 +160,45 @@ func (ml MetalLayer) NextDrawable() (MetalDrawable, error) {
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction
func (ml MetalLayer) PresentsWithTransaction() bool {
return C.MetalLayer_PresentsWithTransaction(ml.metalLayer) != 0
return ml.metalLayer.Send(objc.RegisterName("presentsWithTransaction")) != 0
}
// SetPresentsWithTransaction sets a Boolean value that determines whether the layer presents its content using a Core Animation transaction.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction
func (ml MetalLayer) SetPresentsWithTransaction(presentsWithTransaction bool) {
if presentsWithTransaction {
C.MetalLayer_SetPresentsWithTransaction(ml.metalLayer, 1)
} else {
C.MetalLayer_SetPresentsWithTransaction(ml.metalLayer, 0)
}
ml.metalLayer.Send(objc.RegisterName("setPresentsWithTransaction:"), presentsWithTransaction)
}
// SetFramebufferOnly sets a Boolean value that determines whether the layers textures are used only for rendering.
//
// https://developer.apple.com/documentation/quartzcore/cametallayer/1478168-framebufferonly
func (ml MetalLayer) SetFramebufferOnly(framebufferOnly bool) {
switch framebufferOnly {
case true:
C.MetalLayer_SetFramebufferOnly(ml.metalLayer, 1)
case false:
C.MetalLayer_SetFramebufferOnly(ml.metalLayer, 0)
}
ml.metalLayer.Send(objc.RegisterName("setFramebufferOnly:"), framebufferOnly)
}
// MetalDrawable is a displayable resource that can be rendered or written to by Metal.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable.
type MetalDrawable struct {
metalDrawable unsafe.Pointer
metalDrawable objc.ID
}
// Drawable implements the mtl.Drawable interface.
func (md MetalDrawable) Drawable() unsafe.Pointer { return md.metalDrawable }
func (md MetalDrawable) Drawable() unsafe.Pointer {
return *(*unsafe.Pointer)(unsafe.Pointer(&md.metalDrawable))
}
// Texture returns a Metal texture object representing the drawable object's content.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable/1478159-texture.
func (md MetalDrawable) Texture() mtl.Texture {
return mtl.NewTexture(C.MetalDrawable_Texture(md.metalDrawable))
return mtl.NewTexture(md.metalDrawable.Send(objc.RegisterName("texture")))
}
// Present presents the drawable onscreen as soon as possible.
//
// Reference: https://developer.apple.com/documentation/metal/mtldrawable/1470284-present.
func (md MetalDrawable) Present() {
C.MetalDrawable_Present(md.metalDrawable)
md.metalDrawable.Send(objc.RegisterName("present"))
}

View File

@ -1,37 +0,0 @@
// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
typedef unsigned long uint_t;
void *MakeMetalLayer();
uint16_t MetalLayer_PixelFormat(void *metalLayer);
void MetalLayer_SetDevice(void *metalLayer, void *device);
void MetalLayer_SetOpaque(void *metalLayer, unsigned char opaque);
const char *MetalLayer_SetPixelFormat(void *metalLayer, uint16_t pixelFormat);
const char *MetalLayer_SetMaximumDrawableCount(void *metalLayer,
uint_t maximumDrawableCount);
void MetalLayer_SetDisplaySyncEnabled(void *metalLayer,
uint8_t displaySyncEnabled);
void MetalLayer_SetDrawableSize(void *metalLayer, double width, double height);
void MetalLayer_SetPresentsWithTransaction(void *metalLayer,
uint8_t presentsWithTransaction);
void *MetalLayer_NextDrawable(void *metalLayer);
void MetalLayer_SetFramebufferOnly(void *metalLayer, uint8_t framebufferOnly);
uint8_t MetalLayer_PresentsWithTransaction(void *metalLayer);
void *MetalDrawable_Texture(void *drawable);
void MetalDrawable_Present(void *drawable);

View File

@ -1,116 +0,0 @@
// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ca_darwin.h"
#import <QuartzCore/QuartzCore.h>
void *MakeMetalLayer() {
CAMetalLayer *layer = [[CAMetalLayer alloc] init];
// TODO: Expose a function to set color space.
// TODO: Enable colorspace on iOS: this will be available as of iOS 13.0.
#if !TARGET_OS_IPHONE
CGColorSpaceRef colorspace =
CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3);
layer.colorspace = colorspace;
CGColorSpaceRelease(colorspace);
#endif
return layer;
}
uint16_t MetalLayer_PixelFormat(void *metalLayer) {
return ((CAMetalLayer *)metalLayer).pixelFormat;
}
void MetalLayer_SetDevice(void *metalLayer, void *device) {
((CAMetalLayer *)metalLayer).device = (id<MTLDevice>)device;
}
void MetalLayer_SetOpaque(void *metalLayer, unsigned char opaque) {
((CAMetalLayer *)metalLayer).opaque = (BOOL)opaque;
}
const char *MetalLayer_SetPixelFormat(void *metalLayer, uint16_t pixelFormat) {
@try {
((CAMetalLayer *)metalLayer).pixelFormat = (MTLPixelFormat)pixelFormat;
} @catch (NSException *exception) {
return exception.reason.UTF8String;
}
return NULL;
}
const char *MetalLayer_SetMaximumDrawableCount(void *metalLayer,
uint_t maximumDrawableCount) {
// @available syntax is not available for old Xcode (#781)
//
// If possible, we'd want to write the guard like:
//
// if (@available(macOS 10.13.2, *)) { ...
@try {
if ([(CAMetalLayer *)metalLayer
respondsToSelector:@selector(setMaximumDrawableCount:)]) {
[((CAMetalLayer *)metalLayer)
setMaximumDrawableCount:(NSUInteger)maximumDrawableCount];
}
} @catch (NSException *exception) {
return exception.reason.UTF8String;
}
return NULL;
}
void MetalLayer_SetDisplaySyncEnabled(void *metalLayer,
uint8_t displaySyncEnabled) {
// @available syntax is not available for old Xcode (#781)
//
// If possible, we'd want to write the guard like:
//
// if (@available(macOS 10.13, *)) { ...
#if !TARGET_OS_IPHONE
if ([(CAMetalLayer *)metalLayer
respondsToSelector:@selector(setDisplaySyncEnabled:)]) {
[((CAMetalLayer *)metalLayer) setDisplaySyncEnabled:displaySyncEnabled];
}
#endif
}
void MetalLayer_SetDrawableSize(void *metalLayer, double width, double height) {
((CAMetalLayer *)metalLayer).drawableSize = (CGSize){width, height};
}
void MetalLayer_SetPresentsWithTransaction(void *metalLayer,
uint8_t presentsWithTransaction) {
[((CAMetalLayer *)metalLayer)
setPresentsWithTransaction:presentsWithTransaction];
}
void *MetalLayer_NextDrawable(void *metalLayer) {
return [(CAMetalLayer *)metalLayer nextDrawable];
}
void *MetalDrawable_Texture(void *metalDrawable) {
return ((id<CAMetalDrawable>)metalDrawable).texture;
}
void MetalDrawable_Present(void *metalDrawable) {
[((id<CAMetalDrawable>)metalDrawable) present];
}
void MetalLayer_SetFramebufferOnly(void *metalLayer, uint8_t framebufferOnly) {
[((CAMetalLayer *)metalLayer) setFramebufferOnly:framebufferOnly];
}
uint8_t MetalLayer_PresentsWithTransaction(void *metalLayer) {
return [((CAMetalLayer *)metalLayer) presentsWithTransaction];
}

View File

@ -21,6 +21,7 @@ import (
"strings"
"unsafe"
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca"
@ -28,21 +29,6 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)
// #cgo CFLAGS: -x objective-c
// #cgo !ios CFLAGS: -mmacosx-version-min=10.12
// #cgo LDFLAGS: -framework Foundation
//
// #import <Foundation/Foundation.h>
//
// static void* allocAutoreleasePool() {
// return [[NSAutoreleasePool alloc] init];
// }
//
// static void releaseAutoreleasePool(void* pool) {
// [(NSAutoreleasePool*)pool release];
// }
import "C"
const source = `#include <metal_stdlib>
#define FILTER_NEAREST {{.FilterNearest}}
@ -332,7 +318,7 @@ type Graphics struct {
maxImageSize int
tmpTextures []mtl.Texture
pool unsafe.Pointer
pool cocoa.NSAutoreleasePool
}
type stencilMode int
@ -367,15 +353,15 @@ func NewGraphics() (graphicsdriver.Graphics, error) {
func (g *Graphics) Begin() error {
// NSAutoreleasePool is required to release drawable correctly (#847).
// https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/Drawables.html
g.pool = C.allocAutoreleasePool()
g.pool = cocoa.NSAutoreleasePool_new()
return nil
}
func (g *Graphics) End(present bool) error {
g.flushIfNeeded(present)
g.screenDrawable = ca.MetalDrawable{}
C.releaseAutoreleasePool(g.pool)
g.pool = nil
g.pool.Release()
g.pool.ID = 0
return nil
}

View File

@ -23,11 +23,21 @@ import (
"os"
"unsafe"
"github.com/ebitengine/purego"
"golang.org/x/image/math/f32"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
)
func init() {
// for these tests to pass Metal must be linked directly.
// it is not needed for any of the others nor for Ebitengine to work properly.
//go:cgo_import_dynamic _ _ "Metal.framework/Metal"
// It is also necessary for CoreGraphics to be linked
purego.Dlopen("/System/Library/Frameworks/CoreGraphics.framework/Versions/Current/CoreGraphics", purego.RTLD_GLOBAL)
}
func Example_listDevices() {
device, ok := mtl.CreateSystemDefaultDevice()
if !ok {

View File

@ -25,15 +25,14 @@ package mtl
import (
"errors"
"fmt"
"reflect"
"unsafe"
)
// #cgo !ios CFLAGS: -mmacosx-version-min=10.12
// #cgo LDFLAGS: -framework Metal -framework CoreGraphics -framework Foundation
//
// #include "mtl_darwin.h"
// #include <stdlib.h>
import "C"
"github.com/ebitengine/purego"
"github.com/ebitengine/purego/objc"
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
)
// FeatureSet defines a specific platform, hardware, and software configuration.
//
@ -338,6 +337,11 @@ const (
CommandBufferStatusError CommandBufferStatus = 5 // Execution of the command buffer was aborted due to an error during execution.
)
var (
metal = purego.Dlopen("Metal.framework/Metal", purego.RTLD_GLOBAL)
_MTLCreateSystemDefaultDevice = purego.Dlsym(metal, "MTLCreateSystemDefaultDevice")
)
// Resource represents a memory allocation for storing specialized data
// that is accessible to the GPU.
//
@ -445,7 +449,7 @@ type TextureDescriptor struct {
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice.
type Device struct {
device unsafe.Pointer
device objc.ID
// Headless indicates whether a device is configured as headless.
Headless bool
@ -457,38 +461,133 @@ type Device struct {
Name string
}
var (
class_MTLRenderPipelineDescriptor = objc.GetClass("MTLRenderPipelineDescriptor")
class_MTLTextureDescriptor = objc.GetClass("MTLTextureDescriptor")
class_MTLDepthStencilDescriptor = objc.GetClass("MTLDepthStencilDescriptor")
class_MTLRenderPassDescriptor = objc.GetClass("MTLRenderPassDescriptor")
)
var (
sel_class = objc.RegisterName("class")
sel_length = objc.RegisterName("length")
sel_isHeadless = objc.RegisterName("isHeadless")
sel_isLowPower = objc.RegisterName("isLowPower")
sel_name = objc.RegisterName("name")
sel_supportsFeatureSet = objc.RegisterName("supportsFeatureSet:")
sel_newCommandQueue = objc.RegisterName("newCommandQueue")
sel_newLibraryWithSource_options_error = objc.RegisterName("newLibraryWithSource:options:error:")
sel_release = objc.RegisterName("release")
sel_retain = objc.RegisterName("retain")
sel_new = objc.RegisterName("new")
sel_localizedDescription = objc.RegisterName("localizedDescription")
sel_setVertexFunction = objc.RegisterName("setVertexFunction:")
sel_setFragmentFunction = objc.RegisterName("setFragmentFunction:")
sel_colorAttachments = objc.RegisterName("colorAttachments")
sel_objectAtIndexedSubscript = objc.RegisterName("objectAtIndexedSubscript:")
sel_setPixelFormat = objc.RegisterName("setPixelFormat:")
sel_setBlendingEnabled = objc.RegisterName("setBlendingEnabled:")
sel_setDestinationAlphaBlendFactor = objc.RegisterName("setDestinationAlphaBlendFactor:")
sel_setDestinationRGBBlendFactor = objc.RegisterName("setDestinationRGBBlendFactor:")
sel_setSourceAlphaBlendFactor = objc.RegisterName("setSourceAlphaBlendFactor:")
sel_setSourceRGBBlendFactor = objc.RegisterName("setSourceRGBBlendFactor:")
sel_setWriteMask = objc.RegisterName("setWriteMask:")
sel_setStencilAttachmentPixelFormat = objc.RegisterName("setStencilAttachmentPixelFormat:")
sel_newRenderPipelineStateWithDescriptor_error = objc.RegisterName("newRenderPipelineStateWithDescriptor:error:")
sel_newBufferWithBytes_length_options = objc.RegisterName("newBufferWithBytes:length:options:")
sel_newBufferWithLength_options = objc.RegisterName("newBufferWithLength:options:")
sel_setTextureType = objc.RegisterName("setTextureType:")
sel_didModifyRange = objc.RegisterName("didModifyRange:")
sel_setWidth = objc.RegisterName("setWidth:")
sel_setHeight = objc.RegisterName("setHeight:")
sel_width = objc.RegisterName("width")
sel_height = objc.RegisterName("height")
sel_contents = objc.RegisterName("contents")
sel_setStorageMode = objc.RegisterName("setStorageMode:")
sel_setUsage = objc.RegisterName("setUsage:")
sel_newTextureWithDescriptor = objc.RegisterName("newTextureWithDescriptor:")
sel_commandBuffer = objc.RegisterName("commandBuffer")
sel_status = objc.RegisterName("status")
sel_presentDrawable = objc.RegisterName("presentDrawable:")
sel_commit = objc.RegisterName("commit")
sel_waitUntilCompleted = objc.RegisterName("waitUntilCompleted")
sel_waitUntilScheduled = objc.RegisterName("waitUntilScheduled")
sel_renderCommandEncoderWithDescriptor = objc.RegisterName("renderCommandEncoderWithDescriptor:")
sel_stencilAttachment = objc.RegisterName("stencilAttachment")
sel_setLoadAction = objc.RegisterName("setLoadAction:")
sel_setStoreAction = objc.RegisterName("setStoreAction:")
sel_setTexture = objc.RegisterName("setTexture:")
sel_setClearColor = objc.RegisterName("setClearColor:")
sel_blitCommandEncoder = objc.RegisterName("blitCommandEncoder")
sel_endEncoding = objc.RegisterName("endEncoding")
sel_setRenderPipelineState = objc.RegisterName("setRenderPipelineState:")
sel_setViewport = objc.RegisterName("setViewport:")
sel_setScissorRect = objc.RegisterName("setScissorRect:")
sel_setVertexBuffer_offset_atIndex = objc.RegisterName("setVertexBuffer:offset:atIndex:")
sel_setVertexBytes_length_atIndex = objc.RegisterName("setVertexBytes:length:atIndex:")
sel_setFragmentBytes_length_atIndex = objc.RegisterName("setFragmentBytes:length:atIndex:")
sel_setFragmentTexture_atIndex = objc.RegisterName("setFragmentTexture:atIndex:")
sel_setBlendColorRedGreenBlueAlpha = objc.RegisterName("setBlendColorRed:green:blue:alpha:")
sel_setDepthStencilState = objc.RegisterName("setDepthStencilState:")
sel_drawPrimitives_vertexStart_vertexCount = objc.RegisterName("drawPrimitives:vertexStart:vertexCount:")
sel_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset = objc.RegisterName("drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:")
sel_synchronizeResource = objc.RegisterName("synchronizeResource:")
sel_synchronizeTexture_slice_level = objc.RegisterName("synchronizeTexture:slice:level:")
sel_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin = objc.RegisterName("copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toTexture:destinationSlice:destinationLevel:destinationOrigin:")
sel_newFunctionWithName = objc.RegisterName("newFunctionWithName:")
sel_backFaceStencil = objc.RegisterName("backFaceStencil")
sel_frontFaceStencil = objc.RegisterName("frontFaceStencil")
sel_setStencilFailureOperation = objc.RegisterName("setStencilFailureOperation:")
sel_setDepthFailureOperation = objc.RegisterName("setDepthFailureOperation:")
sel_setDepthStencilPassOperation = objc.RegisterName("setDepthStencilPassOperation:")
sel_setStencilCompareFunction = objc.RegisterName("setStencilCompareFunction:")
sel_newDepthStencilStateWithDescriptor = objc.RegisterName("newDepthStencilStateWithDescriptor:")
sel_replaceRegion_mipmapLevel_withBytes_bytesPerRow = objc.RegisterName("replaceRegion:mipmapLevel:withBytes:bytesPerRow:")
sel_getBytes_bytesPerRow_fromRegion_mipmapLevel = objc.RegisterName("getBytes:bytesPerRow:fromRegion:mipmapLevel:")
)
// CreateSystemDefaultDevice returns the preferred system default Metal device.
//
// Reference: https://developer.apple.com/documentation/metal/1433401-mtlcreatesystemdefaultdevice.
func CreateSystemDefaultDevice() (Device, bool) {
d := C.CreateSystemDefaultDevice()
if d.Device == nil {
d, _, _ := purego.SyscallN(_MTLCreateSystemDefaultDevice)
if d == 0 {
return Device{}, false
}
var (
headless bool
lowPower bool
name string
)
if !cocoa.IsIOS {
headless = int(objc.ID(d).Send(sel_isHeadless)) != 0
lowPower = int(objc.ID(d).Send(sel_isLowPower)) != 0
}
name = cocoa.NSString{ID: objc.ID(d).Send(sel_name)}.String()
return Device{
device: d.Device,
Headless: d.Headless != 0,
LowPower: d.LowPower != 0,
Name: C.GoString(d.Name),
device: objc.ID(d),
Headless: headless,
LowPower: lowPower,
Name: name,
}, true
}
// Device returns the underlying id<MTLDevice> pointer.
func (d Device) Device() unsafe.Pointer { return d.device }
func (d Device) Device() unsafe.Pointer { return *(*unsafe.Pointer)(unsafe.Pointer(&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 d.device.Send(sel_supportsFeatureSet, uintptr(fs)) != 0
}
// MakeCommandQueue creates a serial command submission queue.
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433388-makecommandqueue.
func (d Device) MakeCommandQueue() CommandQueue {
return CommandQueue{C.Device_MakeCommandQueue(d.device)}
return CommandQueue{d.device.Send(sel_newCommandQueue)}
}
// MakeLibrary creates a new library that contains
@ -496,44 +595,47 @@ func (d Device) MakeCommandQueue() CommandQueue {
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433431-makelibrary.
func (d Device) MakeLibrary(source string, opt CompileOptions) (Library, error) {
cs := C.CString(source)
defer C.free(unsafe.Pointer(cs))
l := C.Device_MakeLibrary(d.device, cs, C.size_t(len(source)))
if l.Library == nil {
return Library{}, errors.New(C.GoString(l.Error))
var err cocoa.NSError
l := d.device.Send(
sel_newLibraryWithSource_options_error,
cocoa.NSString_alloc().InitWithUTF8String(source).ID,
0,
unsafe.Pointer(&err),
)
if l == 0 {
return Library{}, errors.New(cocoa.NSString{ID: err.Send(sel_localizedDescription)}.String())
}
return Library{l.Library}, nil
return Library{l}, nil
}
// MakeRenderPipelineState creates a render pipeline state object.
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433369-makerenderpipelinestate.
func (d Device) MakeRenderPipelineState(rpd RenderPipelineDescriptor) (RenderPipelineState, error) {
blendingEnabled := 0
if rpd.ColorAttachments[0].BlendingEnabled {
blendingEnabled = 1
}
c := &rpd.ColorAttachments[0]
descriptor := C.struct_RenderPipelineDescriptor{
VertexFunction: rpd.VertexFunction.function,
FragmentFunction: rpd.FragmentFunction.function,
ColorAttachment0PixelFormat: C.uint16_t(c.PixelFormat),
ColorAttachment0BlendingEnabled: C.uint8_t(blendingEnabled),
ColorAttachment0DestinationAlphaBlendFactor: C.uint8_t(c.DestinationAlphaBlendFactor),
ColorAttachment0DestinationRGBBlendFactor: C.uint8_t(c.DestinationRGBBlendFactor),
ColorAttachment0SourceAlphaBlendFactor: C.uint8_t(c.SourceAlphaBlendFactor),
ColorAttachment0SourceRGBBlendFactor: C.uint8_t(c.SourceRGBBlendFactor),
ColorAttachment0WriteMask: C.uint8_t(c.WriteMask),
StencilAttachmentPixelFormat: C.uint8_t(rpd.StencilAttachmentPixelFormat),
}
rps := C.Device_MakeRenderPipelineState(d.device, descriptor)
if rps.RenderPipelineState == nil {
return RenderPipelineState{}, errors.New(C.GoString(rps.Error))
renderPipelineDescriptor := objc.ID(class_MTLRenderPipelineDescriptor).Send(sel_new)
renderPipelineDescriptor.Send(sel_setVertexFunction, rpd.VertexFunction.function)
renderPipelineDescriptor.Send(sel_setFragmentFunction, rpd.FragmentFunction.function)
colorAttachments0 := renderPipelineDescriptor.Send(sel_colorAttachments).Send(sel_objectAtIndexedSubscript, 0)
colorAttachments0.Send(sel_setPixelFormat, uintptr(rpd.ColorAttachments[0].PixelFormat))
colorAttachments0.Send(sel_setBlendingEnabled, rpd.ColorAttachments[0].BlendingEnabled)
colorAttachments0.Send(sel_setDestinationAlphaBlendFactor, uintptr(rpd.ColorAttachments[0].DestinationAlphaBlendFactor))
colorAttachments0.Send(sel_setDestinationRGBBlendFactor, uintptr(rpd.ColorAttachments[0].DestinationRGBBlendFactor))
colorAttachments0.Send(sel_setSourceAlphaBlendFactor, uintptr(rpd.ColorAttachments[0].SourceAlphaBlendFactor))
colorAttachments0.Send(sel_setSourceRGBBlendFactor, uintptr(rpd.ColorAttachments[0].SourceRGBBlendFactor))
colorAttachments0.Send(sel_setWriteMask, uintptr(rpd.ColorAttachments[0].WriteMask))
renderPipelineDescriptor.Send(sel_setStencilAttachmentPixelFormat, uintptr(rpd.StencilAttachmentPixelFormat))
var err cocoa.NSError
renderPipelineState := d.device.Send(sel_newRenderPipelineStateWithDescriptor_error,
renderPipelineDescriptor,
unsafe.Pointer(&err),
)
renderPipelineDescriptor.Send(sel_release)
if renderPipelineState == 0 {
return RenderPipelineState{}, errors.New(cocoa.NSString{ID: err.Send(sel_localizedDescription)}.String())
}
return RenderPipelineState{rps.RenderPipelineState}, nil
return RenderPipelineState{renderPipelineState}, nil
}
// MakeBufferWithBytes allocates a new buffer of a given length
@ -541,14 +643,14 @@ func (d Device) MakeRenderPipelineState(rpd RenderPipelineDescriptor) (RenderPip
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433429-makebuffer.
func (d Device) MakeBufferWithBytes(bytes unsafe.Pointer, length uintptr, opt ResourceOptions) Buffer {
return Buffer{C.Device_MakeBufferWithBytes(d.device, bytes, C.size_t(length), C.uint16_t(opt))}
return Buffer{d.device.Send(sel_newBufferWithBytes_length_options, bytes, length, uintptr(opt))}
}
// MakeBufferWithLength allocates a new zero-filled buffer of a given length.
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433375-newbufferwithlength
func (d Device) MakeBufferWithLength(length uintptr, opt ResourceOptions) Buffer {
return Buffer{C.Device_MakeBufferWithLength(d.device, C.size_t(length), C.uint16_t(opt))}
return Buffer{d.device.Send(sel_newBufferWithLength_options, length, uintptr(opt))}
}
// MakeTexture creates a texture object with privately owned storage
@ -556,16 +658,17 @@ func (d Device) MakeBufferWithLength(length uintptr, opt ResourceOptions) Buffer
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433425-maketexture.
func (d Device) MakeTexture(td TextureDescriptor) Texture {
descriptor := C.struct_TextureDescriptor{
TextureType: C.uint16_t(td.TextureType),
PixelFormat: C.uint16_t(td.PixelFormat),
Width: C.uint_t(td.Width),
Height: C.uint_t(td.Height),
StorageMode: C.uint8_t(td.StorageMode),
Usage: C.uint8_t(td.Usage),
}
textureDescriptor := objc.ID(class_MTLTextureDescriptor).Send(sel_new)
textureDescriptor.Send(sel_setTextureType, uintptr(td.TextureType))
textureDescriptor.Send(sel_setPixelFormat, uintptr(td.PixelFormat))
textureDescriptor.Send(sel_setWidth, uintptr(td.Width))
textureDescriptor.Send(sel_setHeight, uintptr(td.Height))
textureDescriptor.Send(sel_setStorageMode, uintptr(td.StorageMode))
textureDescriptor.Send(sel_setUsage, uintptr(td.Usage))
texture := d.device.Send(sel_newTextureWithDescriptor, textureDescriptor)
textureDescriptor.Send(sel_release)
return Texture{
texture: C.Device_MakeTexture(d.device, descriptor),
texture: texture,
}
}
@ -573,18 +676,21 @@ func (d Device) MakeTexture(td TextureDescriptor) Texture {
//
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433412-makedepthstencilstate
func (d Device) MakeDepthStencilState(dsd DepthStencilDescriptor) DepthStencilState {
descriptor := C.struct_DepthStencilDescriptor{
BackFaceStencilStencilFailureOperation: C.uint8_t(dsd.BackFaceStencil.StencilFailureOperation),
BackFaceStencilDepthFailureOperation: C.uint8_t(dsd.BackFaceStencil.DepthFailureOperation),
BackFaceStencilDepthStencilPassOperation: C.uint8_t(dsd.BackFaceStencil.DepthStencilPassOperation),
BackFaceStencilStencilCompareFunction: C.uint8_t(dsd.BackFaceStencil.StencilCompareFunction),
FrontFaceStencilStencilFailureOperation: C.uint8_t(dsd.FrontFaceStencil.StencilFailureOperation),
FrontFaceStencilDepthFailureOperation: C.uint8_t(dsd.FrontFaceStencil.DepthFailureOperation),
FrontFaceStencilDepthStencilPassOperation: C.uint8_t(dsd.FrontFaceStencil.DepthStencilPassOperation),
FrontFaceStencilStencilCompareFunction: C.uint8_t(dsd.FrontFaceStencil.StencilCompareFunction),
}
depthStencilDescriptor := objc.ID(class_MTLDepthStencilDescriptor).Send(sel_new)
backFaceStencil := depthStencilDescriptor.Send(sel_backFaceStencil)
backFaceStencil.Send(sel_setStencilFailureOperation, uintptr(dsd.BackFaceStencil.StencilFailureOperation))
backFaceStencil.Send(sel_setDepthFailureOperation, uintptr(dsd.BackFaceStencil.DepthFailureOperation))
backFaceStencil.Send(sel_setDepthStencilPassOperation, uintptr(dsd.BackFaceStencil.DepthStencilPassOperation))
backFaceStencil.Send(sel_setStencilCompareFunction, uintptr(dsd.BackFaceStencil.StencilCompareFunction)) //TODO
frontFaceStencil := depthStencilDescriptor.Send(sel_frontFaceStencil)
frontFaceStencil.Send(sel_setStencilFailureOperation, uintptr(dsd.FrontFaceStencil.StencilFailureOperation))
frontFaceStencil.Send(sel_setDepthFailureOperation, uintptr(dsd.FrontFaceStencil.DepthFailureOperation))
frontFaceStencil.Send(sel_setDepthStencilPassOperation, uintptr(dsd.FrontFaceStencil.DepthStencilPassOperation))
frontFaceStencil.Send(sel_setStencilCompareFunction, uintptr(dsd.FrontFaceStencil.StencilCompareFunction))
depthStencilState := d.device.Send(sel_newDepthStencilStateWithDescriptor, depthStencilDescriptor)
depthStencilDescriptor.Send(sel_release)
return DepthStencilState{
depthStencilState: C.Device_MakeDepthStencilState(d.device, descriptor),
depthStencilState: depthStencilState,
}
}
@ -609,18 +715,18 @@ type Drawable interface {
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandqueue.
type CommandQueue struct {
commandQueue unsafe.Pointer
commandQueue objc.ID
}
func (c CommandQueue) Release() {
C.CommandQueue_Release(c.commandQueue)
func (cq CommandQueue) Release() {
cq.commandQueue.Send(sel_release)
}
// MakeCommandBuffer creates a command buffer.
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandqueue/1508686-makecommandbuffer.
func (cq CommandQueue) MakeCommandBuffer() CommandBuffer {
return CommandBuffer{C.CommandQueue_MakeCommandBuffer(cq.commandQueue)}
return CommandBuffer{cq.commandQueue.Send(sel_commandBuffer)}
}
// CommandBuffer is a container that stores encoded commands
@ -628,50 +734,50 @@ func (cq CommandQueue) MakeCommandBuffer() CommandBuffer {
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer.
type CommandBuffer struct {
commandBuffer unsafe.Pointer
commandBuffer objc.ID
}
func (cb CommandBuffer) Retain() {
C.CommandBuffer_Retain(cb.commandBuffer)
cb.commandBuffer.Send(sel_retain)
}
func (cb CommandBuffer) Release() {
C.CommandBuffer_Release(cb.commandBuffer)
cb.commandBuffer.Send(sel_release)
}
// Status returns the current stage in the lifetime of the command buffer.
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443048-status
func (cb CommandBuffer) Status() CommandBufferStatus {
return CommandBufferStatus(C.CommandBuffer_Status(cb.commandBuffer))
return CommandBufferStatus(cb.commandBuffer.Send(sel_status))
}
// PresentDrawable registers a drawable presentation to occur as soon as possible.
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443029-presentdrawable.
func (cb CommandBuffer) PresentDrawable(d Drawable) {
C.CommandBuffer_PresentDrawable(cb.commandBuffer, d.Drawable())
cb.commandBuffer.Send(sel_presentDrawable, d.Drawable())
}
// Commit commits this command buffer for execution as soon as possible.
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443003-commit.
func (cb CommandBuffer) Commit() {
C.CommandBuffer_Commit(cb.commandBuffer)
cb.commandBuffer.Send(sel_commit)
}
// WaitUntilCompleted waits for the execution of this command buffer to complete.
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443039-waituntilcompleted.
func (cb CommandBuffer) WaitUntilCompleted() {
C.CommandBuffer_WaitUntilCompleted(cb.commandBuffer)
cb.commandBuffer.Send(sel_waitUntilCompleted)
}
// WaitUntilScheduled blocks execution of the current thread until the command buffer is scheduled.
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443036-waituntilscheduled.
func (cb CommandBuffer) WaitUntilScheduled() {
C.CommandBuffer_WaitUntilScheduled(cb.commandBuffer)
cb.commandBuffer.Send(sel_waitUntilScheduled)
}
// MakeRenderCommandEncoder creates an encoder object that can
@ -679,21 +785,24 @@ func (cb CommandBuffer) WaitUntilScheduled() {
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1442999-makerendercommandencoder.
func (cb CommandBuffer) MakeRenderCommandEncoder(rpd RenderPassDescriptor) RenderCommandEncoder {
descriptor := C.struct_RenderPassDescriptor{
ColorAttachment0LoadAction: C.uint8_t(rpd.ColorAttachments[0].LoadAction),
ColorAttachment0StoreAction: C.uint8_t(rpd.ColorAttachments[0].StoreAction),
ColorAttachment0ClearColor: C.struct_ClearColor{
Red: C.double(rpd.ColorAttachments[0].ClearColor.Red),
Green: C.double(rpd.ColorAttachments[0].ClearColor.Green),
Blue: C.double(rpd.ColorAttachments[0].ClearColor.Blue),
Alpha: C.double(rpd.ColorAttachments[0].ClearColor.Alpha),
},
ColorAttachment0Texture: rpd.ColorAttachments[0].Texture.texture,
StencilAttachmentLoadAction: C.uint8_t(rpd.StencilAttachment.LoadAction),
StencilAttachmentStoreAction: C.uint8_t(rpd.StencilAttachment.StoreAction),
StencilAttachmentTexture: rpd.StencilAttachment.Texture.texture,
}
return RenderCommandEncoder{CommandEncoder{C.CommandBuffer_MakeRenderCommandEncoder(cb.commandBuffer, descriptor)}}
var renderPassDescriptor = objc.ID(class_MTLRenderPassDescriptor).Send(sel_new)
var colorAttachments0 = renderPassDescriptor.Send(sel_colorAttachments).Send(sel_objectAtIndexedSubscript, 0)
colorAttachments0.Send(sel_setLoadAction, int(rpd.ColorAttachments[0].LoadAction))
colorAttachments0.Send(sel_setStoreAction, int(rpd.ColorAttachments[0].StoreAction))
colorAttachments0.Send(sel_setTexture, rpd.ColorAttachments[0].Texture.texture)
sig := cocoa.NSMethodSignature_instanceMethodSignatureForSelector(colorAttachments0.Send(sel_class), sel_setClearColor)
inv := cocoa.NSInvocation_invocationWithMethodSignature(sig)
inv.SetTarget(colorAttachments0)
inv.SetSelector(sel_setClearColor)
inv.SetArgumentAtIndex(unsafe.Pointer(&rpd.ColorAttachments[0].ClearColor), 2)
inv.Invoke()
var stencilAttachment = renderPassDescriptor.Send(sel_stencilAttachment)
stencilAttachment.Send(sel_setLoadAction, int(rpd.StencilAttachment.LoadAction))
stencilAttachment.Send(sel_setStoreAction, int(rpd.StencilAttachment.StoreAction))
stencilAttachment.Send(sel_setTexture, rpd.StencilAttachment.Texture.texture)
var rce = cb.commandBuffer.Send(sel_renderCommandEncoderWithDescriptor, renderPassDescriptor)
renderPassDescriptor.Send(sel_release)
return RenderCommandEncoder{CommandEncoder{rce}}
}
// MakeBlitCommandEncoder creates an encoder object that can encode
@ -701,7 +810,8 @@ func (cb CommandBuffer) MakeRenderCommandEncoder(rpd RenderPassDescriptor) Rende
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443001-makeblitcommandencoder.
func (cb CommandBuffer) MakeBlitCommandEncoder() BlitCommandEncoder {
return BlitCommandEncoder{CommandEncoder{C.CommandBuffer_MakeBlitCommandEncoder(cb.commandBuffer)}}
ce := cb.commandBuffer.Send(sel_blitCommandEncoder)
return BlitCommandEncoder{CommandEncoder{ce}}
}
// CommandEncoder is an encoder that writes sequential GPU commands
@ -709,14 +819,14 @@ func (cb CommandBuffer) MakeBlitCommandEncoder() BlitCommandEncoder {
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandencoder.
type CommandEncoder struct {
commandEncoder unsafe.Pointer
commandEncoder objc.ID
}
// EndEncoding declares that all command generation from this encoder is completed.
//
// Reference: https://developer.apple.com/documentation/metal/mtlcommandencoder/1458038-endencoding.
func (ce CommandEncoder) EndEncoding() {
C.CommandEncoder_EndEncoding(ce.commandEncoder)
ce.commandEncoder.Send(sel_endEncoding)
}
// RenderCommandEncoder is an encoder that specifies graphics-rendering commands
@ -728,25 +838,33 @@ type RenderCommandEncoder struct {
}
func (rce RenderCommandEncoder) Release() {
C.RenderCommandEncoder_Release(rce.commandEncoder)
rce.commandEncoder.Send(sel_release)
}
// SetRenderPipelineState sets the current render pipeline state object.
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515811-setrenderpipelinestate.
func (rce RenderCommandEncoder) SetRenderPipelineState(rps RenderPipelineState) {
C.RenderCommandEncoder_SetRenderPipelineState(rce.commandEncoder, rps.renderPipelineState)
rce.commandEncoder.Send(sel_setRenderPipelineState, rps.renderPipelineState)
}
func (rce RenderCommandEncoder) SetViewport(viewport Viewport) {
C.RenderCommandEncoder_SetViewport(rce.commandEncoder, viewport.c())
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:{MTLViewport=dddddd}"))
inv.SetTarget(rce.commandEncoder)
inv.SetSelector(sel_setViewport)
inv.SetArgumentAtIndex(unsafe.Pointer(&viewport), 2)
inv.Invoke()
}
// SetScissorRect sets the scissor rectangle for a fragment scissor test.
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515583-setscissorrect
func (rce RenderCommandEncoder) SetScissorRect(scissorRect ScissorRect) {
C.RenderCommandEncoder_SetScissorRect(rce.commandEncoder, scissorRect.c())
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:{MTLScissorRect=qqqq}"))
inv.SetTarget(rce.commandEncoder)
inv.SetSelector(sel_setScissorRect)
inv.SetArgumentAtIndex(unsafe.Pointer(&scissorRect), 2)
inv.Invoke()
}
// SetVertexBuffer sets a buffer for the vertex shader function at an index
@ -754,36 +872,43 @@ func (rce RenderCommandEncoder) SetScissorRect(scissorRect ScissorRect) {
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515829-setvertexbuffer.
func (rce RenderCommandEncoder) SetVertexBuffer(buf Buffer, offset, index int) {
C.RenderCommandEncoder_SetVertexBuffer(rce.commandEncoder, buf.buffer, C.uint_t(offset), C.uint_t(index))
rce.commandEncoder.Send(sel_setVertexBuffer_offset_atIndex, buf.buffer, offset, index)
}
// SetVertexBytes sets a block of data for the vertex function.
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515846-setvertexbytes.
func (rce RenderCommandEncoder) SetVertexBytes(bytes unsafe.Pointer, length uintptr, index int) {
C.RenderCommandEncoder_SetVertexBytes(rce.commandEncoder, bytes, C.size_t(length), C.uint_t(index))
rce.commandEncoder.Send(sel_setVertexBytes_length_atIndex, bytes, length, index)
}
func (rce RenderCommandEncoder) SetFragmentBytes(bytes unsafe.Pointer, length uintptr, index int) {
C.RenderCommandEncoder_SetFragmentBytes(rce.commandEncoder, bytes, C.size_t(length), C.uint_t(index))
rce.commandEncoder.Send(sel_setFragmentBytes_length_atIndex, bytes, length, index)
}
// SetFragmentTexture sets a texture for the fragment function at an index in the texture argument table.
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515390-setfragmenttexture
func (rce RenderCommandEncoder) SetFragmentTexture(texture Texture, index int) {
C.RenderCommandEncoder_SetFragmentTexture(rce.commandEncoder, texture.texture, C.uint_t(index))
rce.commandEncoder.Send(sel_setFragmentTexture_atIndex, texture.texture, index)
}
func (rce RenderCommandEncoder) SetBlendColor(red, green, blue, alpha float32) {
C.RenderCommandEncoder_SetBlendColor(rce.commandEncoder, C.float(red), C.float(green), C.float(blue), C.float(alpha))
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:ffff"))
inv.SetTarget(rce.commandEncoder)
inv.SetSelector(sel_setBlendColorRedGreenBlueAlpha)
inv.SetArgumentAtIndex(unsafe.Pointer(&red), 2)
inv.SetArgumentAtIndex(unsafe.Pointer(&green), 3)
inv.SetArgumentAtIndex(unsafe.Pointer(&blue), 4)
inv.SetArgumentAtIndex(unsafe.Pointer(&alpha), 5)
inv.Invoke()
}
// SetDepthStencilState sets the depth and stencil test state.
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1516119-setdepthstencilstate
func (rce RenderCommandEncoder) SetDepthStencilState(depthStencilState DepthStencilState) {
C.RenderCommandEncoder_SetDepthStencilState(rce.commandEncoder, depthStencilState.depthStencilState)
rce.commandEncoder.Send(sel_setDepthStencilState, depthStencilState.depthStencilState)
}
// DrawPrimitives renders one instance of primitives using vertex data
@ -791,14 +916,16 @@ func (rce RenderCommandEncoder) SetDepthStencilState(depthStencilState DepthSten
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1516326-drawprimitives.
func (rce RenderCommandEncoder) DrawPrimitives(typ PrimitiveType, vertexStart, vertexCount int) {
C.RenderCommandEncoder_DrawPrimitives(rce.commandEncoder, C.uint8_t(typ), C.uint_t(vertexStart), C.uint_t(vertexCount))
rce.commandEncoder.Send(sel_drawPrimitives_vertexStart_vertexCount, uintptr(typ), vertexStart, vertexCount)
}
// DrawIndexedPrimitives encodes a command to render one instance of primitives using an index list specified in a buffer.
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515542-drawindexedprimitives
func (rce RenderCommandEncoder) DrawIndexedPrimitives(typ PrimitiveType, indexCount int, indexType IndexType, indexBuffer Buffer, indexBufferOffset int) {
C.RenderCommandEncoder_DrawIndexedPrimitives(rce.commandEncoder, C.uint8_t(typ), C.uint_t(indexCount), C.uint8_t(indexType), indexBuffer.buffer, C.uint_t(indexBufferOffset))
rce.commandEncoder.Send(
sel_drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset,
uintptr(typ), indexCount, uintptr(indexType), indexBuffer.buffer, indexBufferOffset)
}
// BlitCommandEncoder is an encoder that specifies resource copy
@ -814,33 +941,52 @@ type BlitCommandEncoder struct {
//
// Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400775-synchronize.
func (bce BlitCommandEncoder) Synchronize(resource Resource) {
C.BlitCommandEncoder_Synchronize(bce.commandEncoder, resource.resource())
if cocoa.IsIOS {
return
}
bce.commandEncoder.Send(sel_synchronizeResource, resource.resource())
}
func (bce BlitCommandEncoder) SynchronizeTexture(texture Texture, slice int, level int) {
C.BlitCommandEncoder_SynchronizeTexture(bce.commandEncoder, texture.texture, C.uint_t(slice), C.uint_t(level))
if cocoa.IsIOS {
return
}
bce.commandEncoder.Send(sel_synchronizeTexture_slice_level, texture.texture, slice, level)
}
func (bce BlitCommandEncoder) CopyFromTexture(sourceTexture Texture, sourceSlice int, sourceLevel int, sourceOrigin Origin, sourceSize Size, destinationTexture Texture, destinationSlice int, destinationLevel int, destinationOrigin Origin) {
C.BlitCommandEncoder_CopyFromTexture(bce.commandEncoder, sourceTexture.texture, C.uint_t(sourceSlice), C.uint_t(sourceLevel), sourceOrigin.c(), sourceSize.c(), destinationTexture.texture, C.uint_t(destinationSlice), C.uint_t(destinationLevel), destinationOrigin.c())
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:@QQ{MTLOrigin=qqq}{MTLSize=qqq}@QQ{MTLOrigin=qqq}"))
inv.SetTarget(bce.commandEncoder)
inv.SetSelector(sel_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin)
inv.SetArgumentAtIndex(unsafe.Pointer(&sourceTexture), 2)
inv.SetArgumentAtIndex(unsafe.Pointer(&sourceSlice), 3)
inv.SetArgumentAtIndex(unsafe.Pointer(&sourceLevel), 4)
inv.SetArgumentAtIndex(unsafe.Pointer(&sourceOrigin), 5)
inv.SetArgumentAtIndex(unsafe.Pointer(&sourceSize), 6)
inv.SetArgumentAtIndex(unsafe.Pointer(&destinationTexture), 7)
inv.SetArgumentAtIndex(unsafe.Pointer(&destinationSlice), 8)
inv.SetArgumentAtIndex(unsafe.Pointer(&destinationLevel), 9)
inv.SetArgumentAtIndex(unsafe.Pointer(&destinationOrigin), 10)
inv.Invoke()
}
// Library is a collection of compiled graphics or compute functions.
//
// Reference: https://developer.apple.com/documentation/metal/mtllibrary.
type Library struct {
library unsafe.Pointer
library objc.ID
}
// MakeFunction returns a pre-compiled, non-specialized function.
//
// Reference: https://developer.apple.com/documentation/metal/mtllibrary/1515524-makefunction.
func (l Library) MakeFunction(name string) (Function, error) {
f := C.Library_MakeFunction(l.library, C.CString(name))
if f == nil {
f := l.library.Send(sel_newFunctionWithName,
cocoa.NSString_alloc().InitWithUTF8String(name).ID,
)
if f == 0 {
return Function{}, fmt.Errorf("function %q not found", name)
}
return Function{f}, nil
}
@ -849,19 +995,19 @@ func (l Library) MakeFunction(name string) (Function, error) {
//
// Reference: https://developer.apple.com/documentation/metal/mtltexture.
type Texture struct {
texture unsafe.Pointer
texture objc.ID
}
// NewTexture returns a Texture that wraps an existing id<MTLTexture> pointer.
func NewTexture(texture unsafe.Pointer) Texture {
func NewTexture(texture objc.ID) Texture {
return Texture{texture: texture}
}
// resource implements the Resource interface.
func (t Texture) resource() unsafe.Pointer { return t.texture }
func (t Texture) resource() unsafe.Pointer { return *(*unsafe.Pointer)(unsafe.Pointer(&t.texture)) }
func (t Texture) Release() {
C.Texture_Release(t.texture)
t.texture.Send(sel_release)
}
// GetBytes copies a block of pixels from the storage allocation of texture
@ -869,30 +1015,42 @@ func (t Texture) Release() {
//
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515751-getbytes.
func (t Texture) GetBytes(pixelBytes *byte, bytesPerRow uintptr, region Region, level int) {
r := region.c()
C.Texture_GetBytes(t.texture, unsafe.Pointer(pixelBytes), C.size_t(bytesPerRow), r, C.uint_t(level))
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:^vQ{MTLRegion={MTLOrigin=qqq}{MTLSize=qqq}}Q"))
inv.SetTarget(t.texture)
inv.SetSelector(sel_getBytes_bytesPerRow_fromRegion_mipmapLevel)
inv.SetArgumentAtIndex(unsafe.Pointer(&pixelBytes), 2)
inv.SetArgumentAtIndex(unsafe.Pointer(&bytesPerRow), 3)
inv.SetArgumentAtIndex(unsafe.Pointer(&region), 4)
inv.SetArgumentAtIndex(unsafe.Pointer(&level), 5)
inv.Invoke()
}
// ReplaceRegion copies a block of pixels from the caller's pointer into the storage allocation for slice 0 of a texture.
//
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515464-replaceregion
func (t Texture) ReplaceRegion(region Region, level int, pixelBytes unsafe.Pointer, bytesPerRow int) {
r := region.c()
C.Texture_ReplaceRegion(t.texture, r, C.uint_t(level), pixelBytes, C.uint_t(bytesPerRow))
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:{MTLRegion={MTLOrigin=qqq}{MTLSize=qqq}}Q^vQ"))
inv.SetTarget(t.texture)
inv.SetSelector(sel_replaceRegion_mipmapLevel_withBytes_bytesPerRow)
inv.SetArgumentAtIndex(unsafe.Pointer(&region), 2)
inv.SetArgumentAtIndex(unsafe.Pointer(&level), 3)
inv.SetArgumentAtIndex(unsafe.Pointer(&pixelBytes), 4)
inv.SetArgumentAtIndex(unsafe.Pointer(&bytesPerRow), 5)
inv.Invoke()
}
// Width is the width of the texture image for the base level mipmap, in pixels.
//
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515339-width
func (t Texture) Width() int {
return int(C.Texture_Width(t.texture))
return int(t.texture.Send(sel_width))
}
// Height is the height of the texture image for the base level mipmap, in pixels.
//
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515938-height
func (t Texture) Height() int {
return int(C.Texture_Height(t.texture))
return int(t.texture.Send(sel_height))
}
// Buffer is a memory allocation for storing unformatted data
@ -900,40 +1058,55 @@ func (t Texture) Height() int {
//
// Reference: https://developer.apple.com/documentation/metal/mtlbuffer.
type Buffer struct {
buffer unsafe.Pointer
buffer objc.ID
}
func (b Buffer) resource() unsafe.Pointer { return b.buffer }
func (b Buffer) resource() unsafe.Pointer { return *(*unsafe.Pointer)(unsafe.Pointer(&b.buffer)) }
func (b Buffer) Length() uintptr {
return uintptr(C.Buffer_Length(b.buffer))
return uintptr(b.buffer.Send(sel_length))
}
func (b Buffer) CopyToContents(data unsafe.Pointer, lengthInBytes uintptr) {
C.Buffer_CopyToContents(b.buffer, data, C.size_t(lengthInBytes))
contents := b.buffer.Send(sel_contents)
// use unsafe.Slice when ebitengine reaches 1.17
var contentSlice []byte
contentHeader := (*reflect.SliceHeader)(unsafe.Pointer(&contentSlice))
contentHeader.Data = uintptr(contents)
contentHeader.Len = int(lengthInBytes)
contentHeader.Cap = int(lengthInBytes)
var dataSlice []byte
dataHeader := (*reflect.SliceHeader)(unsafe.Pointer(&dataSlice))
dataHeader.Data = uintptr(data)
dataHeader.Len = int(lengthInBytes)
dataHeader.Cap = int(lengthInBytes)
copy(contentSlice, dataSlice)
if !cocoa.IsIOS {
b.buffer.Send(sel_didModifyRange, 0, lengthInBytes)
}
}
func (b Buffer) Retain() {
C.Buffer_Retain(b.buffer)
b.buffer.Send(sel_retain)
}
func (b Buffer) Release() {
C.Buffer_Release(b.buffer)
b.buffer.Send(sel_release)
}
func (b Buffer) Native() unsafe.Pointer {
return b.buffer
return *(*unsafe.Pointer)(unsafe.Pointer(&b.buffer))
}
// Function represents a programmable graphics or compute function executed by the GPU.
//
// Reference: https://developer.apple.com/documentation/metal/mtlfunction.
type Function struct {
function unsafe.Pointer
function objc.ID
}
func (f Function) Release() {
C.Function_Release(f.function)
f.function.Send(sel_release)
}
// RenderPipelineState contains the graphics functions
@ -941,11 +1114,11 @@ func (f Function) Release() {
//
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinestate.
type RenderPipelineState struct {
renderPipelineState unsafe.Pointer
renderPipelineState objc.ID
}
func (r RenderPipelineState) Release() {
C.RenderPipelineState_Release(r.renderPipelineState)
r.renderPipelineState.Send(sel_release)
}
// Region is a rectangular block of pixels in an image or texture,
@ -957,41 +1130,18 @@ type Region struct {
Size Size // The size of the block.
}
func (r *Region) c() C.struct_Region {
return C.struct_Region{
Origin: r.Origin.c(),
Size: r.Size.c(),
}
}
// Origin represents the location of a pixel in an image or texture relative
// to the upper-left corner, whose coordinates are (0, 0).
//
// Reference: https://developer.apple.com/documentation/metal/mtlorigin.
type Origin struct{ X, Y, Z int }
func (o *Origin) c() C.struct_Origin {
return C.struct_Origin{
X: C.uint_t(o.X),
Y: C.uint_t(o.Y),
Z: C.uint_t(o.Z),
}
}
// Size represents the set of dimensions that declare the size of an object,
// such as an image, texture, threadgroup, or grid.
//
// Reference: https://developer.apple.com/documentation/metal/mtlsize.
type Size struct{ Width, Height, Depth int }
func (s *Size) c() C.struct_Size {
return C.struct_Size{
Width: C.uint_t(s.Width),
Height: C.uint_t(s.Height),
Depth: C.uint_t(s.Depth),
}
}
// RegionMake2D returns a 2D, rectangular region for image or texture data.
//
// Reference: https://developer.apple.com/documentation/metal/1515675-mtlregionmake2d.
@ -1011,17 +1161,6 @@ type Viewport struct {
ZFar float64
}
func (v *Viewport) c() C.struct_Viewport {
return C.struct_Viewport{
OriginX: C.double(v.OriginX),
OriginY: C.double(v.OriginY),
Width: C.double(v.Width),
Height: C.double(v.Height),
ZNear: C.double(v.ZNear),
ZFar: C.double(v.ZFar),
}
}
// ScissorRect represents a rectangle for the scissor fragment test.
//
// Reference: https://developer.apple.com/documentation/metal/mtlscissorrect
@ -1032,24 +1171,15 @@ type ScissorRect struct {
Height int
}
func (s *ScissorRect) c() C.struct_ScissorRect {
return C.struct_ScissorRect{
X: C.uint_t(s.X),
Y: C.uint_t(s.Y),
Width: C.uint_t(s.Width),
Height: C.uint_t(s.Height),
}
}
// DepthStencilState is a depth and stencil state object that specifies the depth and stencil configuration and operations used in a render pass.
//
// Reference: https://developer.apple.com/documentation/metal/mtldepthstencilstate
type DepthStencilState struct {
depthStencilState unsafe.Pointer
depthStencilState objc.ID
}
func (d DepthStencilState) Release() {
C.DepthStencilState_Release(d.depthStencilState)
d.depthStencilState.Send(sel_release)
}
// DepthStencilDescriptor is an object that configures new MTLDepthStencilState objects.

View File

@ -1,218 +0,0 @@
// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stddef.h>
#include <stdint.h>
typedef unsigned long uint_t;
struct Device {
void *Device;
uint8_t Headless;
uint8_t LowPower;
uint8_t Removable;
uint64_t RegistryID;
const char *Name;
};
struct Devices {
struct Device *Devices;
int Length;
};
struct Library {
void *Library;
const char *Error;
};
struct RenderPipelineDescriptor {
void *VertexFunction;
void *FragmentFunction;
uint16_t ColorAttachment0PixelFormat;
uint8_t ColorAttachment0BlendingEnabled;
uint8_t ColorAttachment0DestinationAlphaBlendFactor;
uint8_t ColorAttachment0DestinationRGBBlendFactor;
uint8_t ColorAttachment0SourceAlphaBlendFactor;
uint8_t ColorAttachment0SourceRGBBlendFactor;
uint8_t ColorAttachment0WriteMask;
uint8_t StencilAttachmentPixelFormat;
};
struct RenderPipelineState {
void *RenderPipelineState;
const char *Error;
};
struct ClearColor {
double Red;
double Green;
double Blue;
double Alpha;
};
struct RenderPassDescriptor {
uint8_t ColorAttachment0LoadAction;
uint8_t ColorAttachment0StoreAction;
struct ClearColor ColorAttachment0ClearColor;
void *ColorAttachment0Texture;
uint8_t StencilAttachmentLoadAction;
uint8_t StencilAttachmentStoreAction;
void *StencilAttachmentTexture;
};
struct TextureDescriptor {
uint16_t TextureType;
uint16_t PixelFormat;
uint_t Width;
uint_t Height;
uint8_t StorageMode;
uint8_t Usage;
};
struct Origin {
uint_t X;
uint_t Y;
uint_t Z;
};
struct Size {
uint_t Width;
uint_t Height;
uint_t Depth;
};
struct Region {
struct Origin Origin;
struct Size Size;
};
struct Viewport {
double OriginX;
double OriginY;
double Width;
double Height;
double ZNear;
double ZFar;
};
struct ScissorRect {
uint_t X;
uint_t Y;
uint_t Width;
uint_t Height;
};
struct DepthStencilDescriptor {
uint8_t BackFaceStencilStencilFailureOperation;
uint8_t BackFaceStencilDepthFailureOperation;
uint8_t BackFaceStencilDepthStencilPassOperation;
uint8_t BackFaceStencilStencilCompareFunction;
uint8_t FrontFaceStencilStencilFailureOperation;
uint8_t FrontFaceStencilDepthFailureOperation;
uint8_t FrontFaceStencilDepthStencilPassOperation;
uint8_t FrontFaceStencilStencilCompareFunction;
};
struct Device CreateSystemDefaultDevice();
struct Devices CopyAllDevices();
uint8_t 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_MakeBufferWithBytes(void *device, const void *bytes, size_t length,
uint16_t options);
void *Device_MakeBufferWithLength(void *device, size_t length,
uint16_t options);
void *Device_MakeTexture(void *device, struct TextureDescriptor descriptor);
void *Device_MakeDepthStencilState(void *device,
struct DepthStencilDescriptor descriptor);
void CommandQueue_Release(void *commandQueue);
void *CommandQueue_MakeCommandBuffer(void *commandQueue);
void CommandBuffer_Retain(void *commandBuffer);
void CommandBuffer_Release(void *commandBuffer);
uint8_t CommandBuffer_Status(void *commandBuffer);
void CommandBuffer_PresentDrawable(void *commandBuffer, void *drawable);
void CommandBuffer_Commit(void *commandBuffer);
void CommandBuffer_WaitUntilCompleted(void *commandBuffer);
void CommandBuffer_WaitUntilScheduled(void *commandBuffer);
void *
CommandBuffer_MakeRenderCommandEncoder(void *commandBuffer,
struct RenderPassDescriptor descriptor);
void *CommandBuffer_MakeBlitCommandEncoder(void *commandBuffer);
void CommandEncoder_EndEncoding(void *commandEncoder);
void RenderCommandEncoder_Release(void *renderCommandEncoder);
void RenderCommandEncoder_SetRenderPipelineState(void *renderCommandEncoder,
void *renderPipelineState);
void RenderCommandEncoder_SetViewport(void *renderCommandEncoder,
struct Viewport viewport);
void RenderCommandEncoder_SetScissorRect(void *renderCommandEncoder,
struct ScissorRect scissorRect);
void RenderCommandEncoder_SetVertexBuffer(void *renderCommandEncoder,
void *buffer, uint_t offset,
uint_t index);
void RenderCommandEncoder_SetVertexBytes(void *renderCommandEncoder,
const void *bytes, size_t length,
uint_t index);
void RenderCommandEncoder_SetFragmentBytes(void *renderCommandEncoder,
const void *bytes, size_t length,
uint_t index);
void RenderCommandEncoder_SetBlendColor(void *renderCommandEncoder, float red,
float green, float blue, float alpha);
void RenderCommandEncoder_SetFragmentTexture(void *renderCommandEncoder,
void *texture, uint_t index);
void RenderCommandEncoder_SetDepthStencilState(void *renderCommandEncoder,
void *depthStencilState);
void RenderCommandEncoder_DrawPrimitives(void *renderCommandEncoder,
uint8_t primitiveType,
uint_t vertexStart,
uint_t vertexCount);
void RenderCommandEncoder_DrawIndexedPrimitives(
void *renderCommandEncoder, uint8_t primitiveType, uint_t indexCount,
uint8_t indexType, void *indexBuffer, uint_t indexBufferOffset);
void BlitCommandEncoder_Synchronize(void *blitCommandEncoder, void *resource);
void BlitCommandEncoder_SynchronizeTexture(void *blitCommandEncoder,
void *texture, uint_t slice,
uint_t level);
void BlitCommandEncoder_CopyFromTexture(
void *blitCommandEncoder, void *sourceTexture, uint_t sourceSlice,
uint_t sourceLevel, struct Origin sourceOrigin, struct Size sourceSize,
void *destinationTexture, uint_t destinationSlice, uint_t destinationLevel,
struct Origin destinationOrigin);
void *Library_MakeFunction(void *library, const char *name);
void Texture_Release(void *texture);
void Texture_GetBytes(void *texture, void *pixelBytes, size_t bytesPerRow,
struct Region region, uint_t level);
void Texture_ReplaceRegion(void *texture, struct Region region, uint_t level,
void *pixelBytes, uint_t bytesPerRow);
int Texture_Width(void *texture);
int Texture_Height(void *texture);
size_t Buffer_Length(void *buffer);
void Buffer_CopyToContents(void *buffer, void *data, size_t lengthInBytes);
void Buffer_Retain(void *buffer);
void Buffer_Release(void *buffer);
void Function_Release(void *function);
void RenderPipelineState_Release(void *renderPipelineState);
void DepthStencilState_Release(void *depthStencilState);

View File

@ -1,439 +0,0 @@
// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "mtl_darwin.h"
#import <Metal/Metal.h>
#include <stdlib.h>
struct Device CreateSystemDefaultDevice() {
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if (!device) {
struct Device d;
d.Device = NULL;
return d;
}
struct Device d;
d.Device = device;
#if !TARGET_OS_IPHONE
d.Headless = device.headless;
d.LowPower = device.lowPower;
#else
d.Headless = 0;
d.LowPower = 0;
#endif
d.Name = device.name.UTF8String;
return d;
}
uint8_t Device_SupportsFeatureSet(void *device, uint16_t featureSet) {
return [(id<MTLDevice>)device supportsFeatureSet:featureSet];
}
void *Device_MakeCommandQueue(void *device) {
return [(id<MTLDevice>)device newCommandQueue];
}
struct Library Device_MakeLibrary(void *device, const char *source,
size_t sourceLength) {
NSError *error;
id<MTLLibrary> library = [(id<MTLDevice>)device
newLibraryWithSource:[[NSString alloc] initWithBytes:source
length:sourceLength
encoding:NSUTF8StringEncoding]
options:NULL
error:&error];
struct Library l;
l.Library = library;
if (!library) {
l.Error = error.localizedDescription.UTF8String;
}
return l;
}
struct RenderPipelineState
Device_MakeRenderPipelineState(void *device,
struct RenderPipelineDescriptor descriptor) {
MTLRenderPipelineDescriptor *renderPipelineDescriptor =
[[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDescriptor.vertexFunction = descriptor.VertexFunction;
renderPipelineDescriptor.fragmentFunction = descriptor.FragmentFunction;
renderPipelineDescriptor.colorAttachments[0].pixelFormat =
descriptor.ColorAttachment0PixelFormat;
renderPipelineDescriptor.colorAttachments[0].blendingEnabled =
descriptor.ColorAttachment0BlendingEnabled;
renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor =
descriptor.ColorAttachment0DestinationAlphaBlendFactor;
renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor =
descriptor.ColorAttachment0DestinationRGBBlendFactor;
renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor =
descriptor.ColorAttachment0SourceAlphaBlendFactor;
renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor =
descriptor.ColorAttachment0SourceRGBBlendFactor;
renderPipelineDescriptor.colorAttachments[0].writeMask =
descriptor.ColorAttachment0WriteMask;
renderPipelineDescriptor.stencilAttachmentPixelFormat =
descriptor.StencilAttachmentPixelFormat;
NSError *error;
id<MTLRenderPipelineState> renderPipelineState = [(id<MTLDevice>)device
newRenderPipelineStateWithDescriptor:renderPipelineDescriptor
error:&error];
[renderPipelineDescriptor release];
struct RenderPipelineState rps;
rps.RenderPipelineState = renderPipelineState;
if (!renderPipelineState) {
rps.Error = error.localizedDescription.UTF8String;
}
return rps;
}
void *Device_MakeBufferWithBytes(void *device, const void *bytes, size_t length,
uint16_t options) {
return [(id<MTLDevice>)device newBufferWithBytes:(const void *)bytes
length:(NSUInteger)length
options:(MTLResourceOptions)options];
}
void *Device_MakeBufferWithLength(void *device, size_t length,
uint16_t options) {
return
[(id<MTLDevice>)device newBufferWithLength:(NSUInteger)length
options:(MTLResourceOptions)options];
}
void *Device_MakeTexture(void *device, struct TextureDescriptor descriptor) {
MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];
textureDescriptor.textureType = descriptor.TextureType;
textureDescriptor.pixelFormat = descriptor.PixelFormat;
textureDescriptor.width = descriptor.Width;
textureDescriptor.height = descriptor.Height;
textureDescriptor.storageMode = descriptor.StorageMode;
textureDescriptor.usage = descriptor.Usage;
id<MTLTexture> texture =
[(id<MTLDevice>)device newTextureWithDescriptor:textureDescriptor];
[textureDescriptor release];
return texture;
}
void *Device_MakeDepthStencilState(void *device,
struct DepthStencilDescriptor descriptor) {
MTLDepthStencilDescriptor *depthStencilDescriptor =
[[MTLDepthStencilDescriptor alloc] init];
depthStencilDescriptor.backFaceStencil.stencilFailureOperation =
descriptor.BackFaceStencilStencilFailureOperation;
depthStencilDescriptor.backFaceStencil.depthFailureOperation =
descriptor.BackFaceStencilDepthFailureOperation;
depthStencilDescriptor.backFaceStencil.depthStencilPassOperation =
descriptor.BackFaceStencilDepthStencilPassOperation;
depthStencilDescriptor.backFaceStencil.stencilCompareFunction =
descriptor.BackFaceStencilStencilCompareFunction;
depthStencilDescriptor.frontFaceStencil.stencilFailureOperation =
descriptor.FrontFaceStencilStencilFailureOperation;
depthStencilDescriptor.frontFaceStencil.depthFailureOperation =
descriptor.FrontFaceStencilDepthFailureOperation;
depthStencilDescriptor.frontFaceStencil.depthStencilPassOperation =
descriptor.FrontFaceStencilDepthStencilPassOperation;
depthStencilDescriptor.frontFaceStencil.stencilCompareFunction =
descriptor.FrontFaceStencilStencilCompareFunction;
id<MTLDepthStencilState> depthStencilState = [(id<MTLDevice>)device
newDepthStencilStateWithDescriptor:depthStencilDescriptor];
[depthStencilDescriptor release];
return depthStencilState;
}
void CommandQueue_Release(void *commandQueue) {
[(id<MTLCommandQueue>)commandQueue release];
}
void *CommandQueue_MakeCommandBuffer(void *commandQueue) {
return [(id<MTLCommandQueue>)commandQueue commandBuffer];
}
void CommandBuffer_Retain(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer retain];
}
void CommandBuffer_Release(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer release];
}
uint8_t CommandBuffer_Status(void *commandBuffer) {
return [(id<MTLCommandBuffer>)commandBuffer status];
}
void CommandBuffer_PresentDrawable(void *commandBuffer, void *drawable) {
[(id<MTLCommandBuffer>)commandBuffer
presentDrawable:(id<MTLDrawable>)drawable];
}
void CommandBuffer_Commit(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer commit];
}
void CommandBuffer_WaitUntilCompleted(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer waitUntilCompleted];
}
void CommandBuffer_WaitUntilScheduled(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer waitUntilScheduled];
}
void *
CommandBuffer_MakeRenderCommandEncoder(void *commandBuffer,
struct RenderPassDescriptor descriptor) {
MTLRenderPassDescriptor *renderPassDescriptor =
[[MTLRenderPassDescriptor alloc] init];
renderPassDescriptor.colorAttachments[0].loadAction =
descriptor.ColorAttachment0LoadAction;
renderPassDescriptor.colorAttachments[0].storeAction =
descriptor.ColorAttachment0StoreAction;
renderPassDescriptor.colorAttachments[0].clearColor =
MTLClearColorMake(descriptor.ColorAttachment0ClearColor.Red,
descriptor.ColorAttachment0ClearColor.Green,
descriptor.ColorAttachment0ClearColor.Blue,
descriptor.ColorAttachment0ClearColor.Alpha);
renderPassDescriptor.colorAttachments[0].texture =
(id<MTLTexture>)descriptor.ColorAttachment0Texture;
renderPassDescriptor.stencilAttachment.loadAction =
descriptor.StencilAttachmentLoadAction;
renderPassDescriptor.stencilAttachment.storeAction =
descriptor.StencilAttachmentStoreAction;
renderPassDescriptor.stencilAttachment.texture =
(id<MTLTexture>)descriptor.StencilAttachmentTexture;
id<MTLRenderCommandEncoder> rce = [(id<MTLCommandBuffer>)commandBuffer
renderCommandEncoderWithDescriptor:renderPassDescriptor];
[renderPassDescriptor release];
return rce;
}
void *CommandBuffer_MakeBlitCommandEncoder(void *commandBuffer) {
return [(id<MTLCommandBuffer>)commandBuffer blitCommandEncoder];
}
void CommandEncoder_EndEncoding(void *commandEncoder) {
[(id<MTLCommandEncoder>)commandEncoder endEncoding];
}
void RenderCommandEncoder_Release(void *renderCommandEncoder) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder release];
}
void RenderCommandEncoder_SetRenderPipelineState(void *renderCommandEncoder,
void *renderPipelineState) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setRenderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState];
}
void RenderCommandEncoder_SetViewport(void *renderCommandEncoder,
struct Viewport viewport) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setViewport:(MTLViewport){
.originX = viewport.OriginX,
.originY = viewport.OriginY,
.width = viewport.Width,
.height = viewport.Height,
.znear = viewport.ZNear,
.zfar = viewport.ZFar,
}];
}
void RenderCommandEncoder_SetScissorRect(void *renderCommandEncoder,
struct ScissorRect scissorRect) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setScissorRect:(MTLScissorRect){
.x = scissorRect.X,
.y = scissorRect.Y,
.width = scissorRect.Width,
.height = scissorRect.Height,
}];
}
void RenderCommandEncoder_SetVertexBuffer(void *renderCommandEncoder,
void *buffer, uint_t offset,
uint_t index) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setVertexBuffer:(id<MTLBuffer>)buffer
offset:(NSUInteger)offset
atIndex:(NSUInteger)index];
}
void RenderCommandEncoder_SetVertexBytes(void *renderCommandEncoder,
const void *bytes, size_t length,
uint_t index) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setVertexBytes:bytes
length:(NSUInteger)length
atIndex:(NSUInteger)index];
}
void RenderCommandEncoder_SetFragmentBytes(void *renderCommandEncoder,
const void *bytes, size_t length,
uint_t index) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setFragmentBytes:bytes
length:(NSUInteger)length
atIndex:(NSUInteger)index];
}
void RenderCommandEncoder_SetFragmentTexture(void *renderCommandEncoder,
void *texture, uint_t index) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setFragmentTexture:(id<MTLTexture>)texture
atIndex:(NSUInteger)index];
}
void RenderCommandEncoder_SetBlendColor(void *renderCommandEncoder, float red,
float green, float blue, float alpha) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder setBlendColorRed:red
green:green
blue:blue
alpha:alpha];
}
void RenderCommandEncoder_SetDepthStencilState(void *renderCommandEncoder,
void *depthStencilState) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setDepthStencilState:(id<MTLDepthStencilState>)depthStencilState];
}
void RenderCommandEncoder_DrawPrimitives(void *renderCommandEncoder,
uint8_t primitiveType,
uint_t vertexStart,
uint_t vertexCount) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
drawPrimitives:(MTLPrimitiveType)primitiveType
vertexStart:(NSUInteger)vertexStart
vertexCount:(NSUInteger)vertexCount];
}
void RenderCommandEncoder_DrawIndexedPrimitives(
void *renderCommandEncoder, uint8_t primitiveType, uint_t indexCount,
uint8_t indexType, void *indexBuffer, uint_t indexBufferOffset) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
drawIndexedPrimitives:(MTLPrimitiveType)primitiveType
indexCount:(NSUInteger)indexCount
indexType:(MTLIndexType)indexType
indexBuffer:(id<MTLBuffer>)indexBuffer
indexBufferOffset:(NSUInteger)indexBufferOffset];
}
void BlitCommandEncoder_Synchronize(void *blitCommandEncoder, void *resource) {
#if !TARGET_OS_IPHONE
[(id<MTLBlitCommandEncoder>)blitCommandEncoder
synchronizeResource:(id<MTLResource>)resource];
#endif
}
void BlitCommandEncoder_SynchronizeTexture(void *blitCommandEncoder,
void *texture, uint_t slice,
uint_t level) {
#if !TARGET_OS_IPHONE
[(id<MTLBlitCommandEncoder>)blitCommandEncoder
synchronizeTexture:(id<MTLTexture>)texture
slice:(NSUInteger)slice
level:(NSUInteger)level];
#endif
}
void BlitCommandEncoder_CopyFromTexture(
void *blitCommandEncoder, void *sourceTexture, uint_t sourceSlice,
uint_t sourceLevel, struct Origin sourceOrigin, struct Size sourceSize,
void *destinationTexture, uint_t destinationSlice, uint_t destinationLevel,
struct Origin destinationOrigin) {
[(id<MTLBlitCommandEncoder>)blitCommandEncoder
copyFromTexture:(id<MTLTexture>)sourceTexture
sourceSlice:(NSUInteger)sourceSlice
sourceLevel:(NSUInteger)sourceLevel
sourceOrigin:(MTLOrigin){.x = sourceOrigin.X,
.y = sourceOrigin.Y,
.z = sourceOrigin.Z}
sourceSize:(MTLSize){.width = sourceSize.Width,
.height = sourceSize.Height,
.depth = sourceSize.Depth}
toTexture:(id<MTLTexture>)destinationTexture
destinationSlice:(NSUInteger)destinationSlice
destinationLevel:(NSUInteger)destinationLevel
destinationOrigin:(MTLOrigin){.x = destinationOrigin.X,
.y = destinationOrigin.Y,
.z = destinationOrigin.Z}];
}
void *Library_MakeFunction(void *library, const char *name) {
return [(id<MTLLibrary>)library
newFunctionWithName:[NSString stringWithUTF8String:name]];
}
void Texture_Release(void *texture) { [(id<MTLTexture>)texture release]; }
void Texture_GetBytes(void *texture, void *pixelBytes, size_t bytesPerRow,
struct Region region, uint_t level) {
[(id<MTLTexture>)texture getBytes:(void *)pixelBytes
bytesPerRow:(NSUInteger)bytesPerRow
fromRegion:(MTLRegion) {
.origin = {.x = region.Origin.X,
.y = region.Origin.Y,
.z = region.Origin.Z},
.size = {
.width = region.Size.Width,
.height = region.Size.Height,
.depth = region.Size.Depth
}
}
mipmapLevel:(NSUInteger)level];
}
void Texture_ReplaceRegion(void *texture, struct Region region, uint_t level,
void *bytes, uint_t bytesPerRow) {
[(id<MTLTexture>)texture replaceRegion:(MTLRegion) {
.origin = {.x = region.Origin.X,
.y = region.Origin.Y,
.z = region.Origin.Z},
.size = {
.width = region.Size.Width,
.height = region.Size.Height,
.depth = region.Size.Depth
}
}
mipmapLevel:(NSUInteger)level
withBytes:bytes
bytesPerRow:(NSUInteger)bytesPerRow];
}
int Texture_Width(void *texture) { return [(id<MTLTexture>)texture width]; }
int Texture_Height(void *texture) { return [(id<MTLTexture>)texture height]; }
size_t Buffer_Length(void *buffer) { return [(id<MTLBuffer>)buffer length]; }
void Buffer_CopyToContents(void *buffer, void *data, size_t lengthInBytes) {
memcpy(((id<MTLBuffer>)buffer).contents, data, lengthInBytes);
#if !TARGET_OS_IPHONE
[(id<MTLBuffer>)buffer didModifyRange:NSMakeRange(0, lengthInBytes)];
#endif
}
void Buffer_Retain(void *buffer) { [(id<MTLBuffer>)buffer retain]; }
void Buffer_Release(void *buffer) { [(id<MTLBuffer>)buffer release]; }
void Function_Release(void *function) { [(id<MTLFunction>)function release]; }
void RenderPipelineState_Release(void *renderPipelineState) {
[(id<MTLRenderPipelineState>)renderPipelineState release];
}
void DepthStencilState_Release(void *depthStencilState) {
[(id<MTLDepthStencilState>)depthStencilState release];
}

View File

@ -20,16 +20,10 @@
package ns
import (
"unsafe"
"github.com/ebitengine/purego/objc"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca"
)
// #cgo !ios CFLAGS: -mmacosx-version-min=10.12
//
// #include "ns_darwin.h"
import "C"
// Window is a window that an app displays on the screen.
//
// Reference: https://developer.apple.com/documentation/appkit/nswindow.
@ -47,37 +41,33 @@ func NewWindow(window uintptr) Window {
//
// Reference: https://developer.apple.com/documentation/appkit/nswindow/1419160-contentview.
func (w Window) ContentView() View {
return View{C.Window_ContentView(C.uintptr_t(w.window))}
return View{objc.ID(w.window).Send(objc.RegisterName("contentView"))}
}
// View is the infrastructure for drawing, printing, and handling events in an app.
//
// Reference: https://developer.apple.com/documentation/appkit/nsview.
type View struct {
view unsafe.Pointer
view objc.ID
}
// SetLayer sets v.layer to l.
//
// Reference: https://developer.apple.com/documentation/appkit/nsview/1483298-layer.
func (v View) SetLayer(l ca.Layer) {
C.View_SetLayer(v.view, l.Layer())
v.view.Send(objc.RegisterName("setLayer:"), uintptr(l.Layer()))
}
// SetWantsLayer sets v.wantsLayer to wantsLayer.
//
// Reference: https://developer.apple.com/documentation/appkit/nsview/1483695-wantslayer.
func (v View) SetWantsLayer(wantsLayer bool) {
if wantsLayer {
C.View_SetWantsLayer(v.view, 1)
} else {
C.View_SetWantsLayer(v.view, 0)
}
v.view.Send(objc.RegisterName("setWantsLayer:"), wantsLayer)
}
// IsInFullScreenMode returns a boolean value indicating whether the view is in full screen mode.
//
// Reference: https://developer.apple.com/documentation/appkit/nsview/1483337-infullscreenmode.
func (v View) IsInFullScreenMode() bool {
return C.View_IsInFullScreenMode(v.view) != 0
return v.view.Send(objc.RegisterName("isInFullScreenMode")) != 0
}

View File

@ -17,8 +17,11 @@
package metal
// #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework UIKit
// Suppress the warnings about availability guard with -Wno-unguarded-availability-new.
// It is because old Xcode (8 or older?) does not accept @available syntax.
// #cgo CFLAGS: -Wno-unguarded-availability-new -x objective-c
// #cgo LDFLAGS: -framework UIKit -framework QuartzCore -framework Foundation -framework CoreGraphics
//
// #import <UIKit/UIKit.h>
//