diff --git a/go.mod b/go.mod index c03666251e0f..9ec17769a26e 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index c5967bc1a9dc..8d98123a05b2 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/internal/cocoa/api_cocoa_darwin.go b/internal/cocoa/api_cocoa_darwin.go new file mode 100644 index 000000000000..b2276cab750c --- /dev/null +++ b/internal/cocoa/api_cocoa_darwin.go @@ -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) +} diff --git a/internal/graphicsdriver/metal/ns/ns_darwin.h b/internal/cocoa/ios_darwin.go similarity index 68% rename from internal/graphicsdriver/metal/ns/ns_darwin.h rename to internal/cocoa/ios_darwin.go index 012c6f118950..fc1b012e4d86 100644 --- a/internal/graphicsdriver/metal/ns/ns_darwin.h +++ b/internal/cocoa/ios_darwin.go @@ -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 diff --git a/internal/graphicsdriver/metal/ns/ns_darwin.m b/internal/cocoa/notios_darwin.go similarity index 53% rename from internal/graphicsdriver/metal/ns/ns_darwin.m rename to internal/cocoa/notios_darwin.go index 6bb0559ff47c..5186e8b0df57 100644 --- a/internal/graphicsdriver/metal/ns/ns_darwin.m +++ b/internal/cocoa/notios_darwin.go @@ -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 +//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 diff --git a/internal/graphicsdriver/metal/ca/ca_darwin.go b/internal/graphicsdriver/metal/ca/ca_darwin.go index 88f5d9171003..06ccc24f402c 100644 --- a/internal/graphicsdriver/metal/ca/ca_darwin.go +++ b/internal/graphicsdriver/metal/ca/ca_darwin.go @@ -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 layer’s 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")) } diff --git a/internal/graphicsdriver/metal/ca/ca_darwin.h b/internal/graphicsdriver/metal/ca/ca_darwin.h deleted file mode 100644 index af87130bc748..000000000000 --- a/internal/graphicsdriver/metal/ca/ca_darwin.h +++ /dev/null @@ -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 - -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); diff --git a/internal/graphicsdriver/metal/ca/ca_darwin.m b/internal/graphicsdriver/metal/ca/ca_darwin.m deleted file mode 100644 index 89ae70b0442e..000000000000 --- a/internal/graphicsdriver/metal/ca/ca_darwin.m +++ /dev/null @@ -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 - -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)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)metalDrawable).texture; -} - -void MetalDrawable_Present(void *metalDrawable) { - [((id)metalDrawable) present]; -} - -void MetalLayer_SetFramebufferOnly(void *metalLayer, uint8_t framebufferOnly) { - [((CAMetalLayer *)metalLayer) setFramebufferOnly:framebufferOnly]; -} - -uint8_t MetalLayer_PresentsWithTransaction(void *metalLayer) { - return [((CAMetalLayer *)metalLayer) presentsWithTransaction]; -} diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 28dfdaeba55a..c39c7d3c64cd 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -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 -// -// static void* allocAutoreleasePool() { -// return [[NSAutoreleasePool alloc] init]; -// } -// -// static void releaseAutoreleasePool(void* pool) { -// [(NSAutoreleasePool*)pool release]; -// } -import "C" - const source = `#include #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 } diff --git a/internal/graphicsdriver/metal/mtl/example_darwin_test.go b/internal/graphicsdriver/metal/mtl/example_darwin_test.go index 04c46b3a67cd..6a0d77b14ea2 100644 --- a/internal/graphicsdriver/metal/mtl/example_darwin_test.go +++ b/internal/graphicsdriver/metal/mtl/example_darwin_test.go @@ -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 { diff --git a/internal/graphicsdriver/metal/mtl/mtl_darwin.go b/internal/graphicsdriver/metal/mtl/mtl_darwin.go index ebaa19ad396b..788793e57cbb 100644 --- a/internal/graphicsdriver/metal/mtl/mtl_darwin.go +++ b/internal/graphicsdriver/metal/mtl/mtl_darwin.go @@ -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 -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 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 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(®ion), 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(®ion), 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. diff --git a/internal/graphicsdriver/metal/mtl/mtl_darwin.h b/internal/graphicsdriver/metal/mtl/mtl_darwin.h deleted file mode 100644 index 33d3565d8d05..000000000000 --- a/internal/graphicsdriver/metal/mtl/mtl_darwin.h +++ /dev/null @@ -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 -#include - -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); diff --git a/internal/graphicsdriver/metal/mtl/mtl_darwin.m b/internal/graphicsdriver/metal/mtl/mtl_darwin.m deleted file mode 100644 index 49cb8d1513c0..000000000000 --- a/internal/graphicsdriver/metal/mtl/mtl_darwin.m +++ /dev/null @@ -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 -#include - -struct Device CreateSystemDefaultDevice() { - id 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)device supportsFeatureSet:featureSet]; -} - -void *Device_MakeCommandQueue(void *device) { - return [(id)device newCommandQueue]; -} - -struct Library Device_MakeLibrary(void *device, const char *source, - size_t sourceLength) { - NSError *error; - id library = [(id)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 renderPipelineState = [(id)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)device newBufferWithBytes:(const void *)bytes - length:(NSUInteger)length - options:(MTLResourceOptions)options]; -} - -void *Device_MakeBufferWithLength(void *device, size_t length, - uint16_t options) { - return - [(id)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 texture = - [(id)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 depthStencilState = [(id)device - newDepthStencilStateWithDescriptor:depthStencilDescriptor]; - [depthStencilDescriptor release]; - return depthStencilState; -} - -void CommandQueue_Release(void *commandQueue) { - [(id)commandQueue release]; -} - -void *CommandQueue_MakeCommandBuffer(void *commandQueue) { - return [(id)commandQueue commandBuffer]; -} - -void CommandBuffer_Retain(void *commandBuffer) { - [(id)commandBuffer retain]; -} - -void CommandBuffer_Release(void *commandBuffer) { - [(id)commandBuffer release]; -} - -uint8_t CommandBuffer_Status(void *commandBuffer) { - return [(id)commandBuffer status]; -} - -void CommandBuffer_PresentDrawable(void *commandBuffer, void *drawable) { - [(id)commandBuffer - presentDrawable:(id)drawable]; -} - -void CommandBuffer_Commit(void *commandBuffer) { - [(id)commandBuffer commit]; -} - -void CommandBuffer_WaitUntilCompleted(void *commandBuffer) { - [(id)commandBuffer waitUntilCompleted]; -} - -void CommandBuffer_WaitUntilScheduled(void *commandBuffer) { - [(id)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)descriptor.ColorAttachment0Texture; - renderPassDescriptor.stencilAttachment.loadAction = - descriptor.StencilAttachmentLoadAction; - renderPassDescriptor.stencilAttachment.storeAction = - descriptor.StencilAttachmentStoreAction; - renderPassDescriptor.stencilAttachment.texture = - (id)descriptor.StencilAttachmentTexture; - id rce = [(id)commandBuffer - renderCommandEncoderWithDescriptor:renderPassDescriptor]; - [renderPassDescriptor release]; - return rce; -} - -void *CommandBuffer_MakeBlitCommandEncoder(void *commandBuffer) { - return [(id)commandBuffer blitCommandEncoder]; -} - -void CommandEncoder_EndEncoding(void *commandEncoder) { - [(id)commandEncoder endEncoding]; -} - -void RenderCommandEncoder_Release(void *renderCommandEncoder) { - [(id)renderCommandEncoder release]; -} - -void RenderCommandEncoder_SetRenderPipelineState(void *renderCommandEncoder, - void *renderPipelineState) { - [(id)renderCommandEncoder - setRenderPipelineState:(id)renderPipelineState]; -} - -void RenderCommandEncoder_SetViewport(void *renderCommandEncoder, - struct Viewport viewport) { - [(id)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)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)renderCommandEncoder - setVertexBuffer:(id)buffer - offset:(NSUInteger)offset - atIndex:(NSUInteger)index]; -} - -void RenderCommandEncoder_SetVertexBytes(void *renderCommandEncoder, - const void *bytes, size_t length, - uint_t index) { - [(id)renderCommandEncoder - setVertexBytes:bytes - length:(NSUInteger)length - atIndex:(NSUInteger)index]; -} - -void RenderCommandEncoder_SetFragmentBytes(void *renderCommandEncoder, - const void *bytes, size_t length, - uint_t index) { - [(id)renderCommandEncoder - setFragmentBytes:bytes - length:(NSUInteger)length - atIndex:(NSUInteger)index]; -} - -void RenderCommandEncoder_SetFragmentTexture(void *renderCommandEncoder, - void *texture, uint_t index) { - [(id)renderCommandEncoder - setFragmentTexture:(id)texture - atIndex:(NSUInteger)index]; -} - -void RenderCommandEncoder_SetBlendColor(void *renderCommandEncoder, float red, - float green, float blue, float alpha) { - [(id)renderCommandEncoder setBlendColorRed:red - green:green - blue:blue - alpha:alpha]; -} - -void RenderCommandEncoder_SetDepthStencilState(void *renderCommandEncoder, - void *depthStencilState) { - [(id)renderCommandEncoder - setDepthStencilState:(id)depthStencilState]; -} - -void RenderCommandEncoder_DrawPrimitives(void *renderCommandEncoder, - uint8_t primitiveType, - uint_t vertexStart, - uint_t vertexCount) { - [(id)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)renderCommandEncoder - drawIndexedPrimitives:(MTLPrimitiveType)primitiveType - indexCount:(NSUInteger)indexCount - indexType:(MTLIndexType)indexType - indexBuffer:(id)indexBuffer - indexBufferOffset:(NSUInteger)indexBufferOffset]; -} - -void BlitCommandEncoder_Synchronize(void *blitCommandEncoder, void *resource) { -#if !TARGET_OS_IPHONE - [(id)blitCommandEncoder - synchronizeResource:(id)resource]; -#endif -} - -void BlitCommandEncoder_SynchronizeTexture(void *blitCommandEncoder, - void *texture, uint_t slice, - uint_t level) { -#if !TARGET_OS_IPHONE - [(id)blitCommandEncoder - synchronizeTexture:(id)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)blitCommandEncoder - copyFromTexture:(id)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)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)library - newFunctionWithName:[NSString stringWithUTF8String:name]]; -} - -void Texture_Release(void *texture) { [(id)texture release]; } - -void Texture_GetBytes(void *texture, void *pixelBytes, size_t bytesPerRow, - struct Region region, uint_t level) { - [(id)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)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)texture width]; } - -int Texture_Height(void *texture) { return [(id)texture height]; } - -size_t Buffer_Length(void *buffer) { return [(id)buffer length]; } - -void Buffer_CopyToContents(void *buffer, void *data, size_t lengthInBytes) { - memcpy(((id)buffer).contents, data, lengthInBytes); -#if !TARGET_OS_IPHONE - [(id)buffer didModifyRange:NSMakeRange(0, lengthInBytes)]; -#endif -} - -void Buffer_Retain(void *buffer) { [(id)buffer retain]; } - -void Buffer_Release(void *buffer) { [(id)buffer release]; } - -void Function_Release(void *function) { [(id)function release]; } - -void RenderPipelineState_Release(void *renderPipelineState) { - [(id)renderPipelineState release]; -} - -void DepthStencilState_Release(void *depthStencilState) { - [(id)depthStencilState release]; -} diff --git a/internal/graphicsdriver/metal/ns/ns_darwin.go b/internal/graphicsdriver/metal/ns/ns_darwin.go index 0c83bbac6088..1d693fd97cb4 100644 --- a/internal/graphicsdriver/metal/ns/ns_darwin.go +++ b/internal/graphicsdriver/metal/ns/ns_darwin.go @@ -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 } diff --git a/internal/graphicsdriver/metal/view_ios.go b/internal/graphicsdriver/metal/view_ios.go index 1c2aceb13b43..62bd39b33f51 100644 --- a/internal/graphicsdriver/metal/view_ios.go +++ b/internal/graphicsdriver/metal/view_ios.go @@ -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 //