diff --git a/internal/cocoa/api_cocoa_darwin.go b/internal/cocoa/api_cocoa_darwin.go index 51ce6d30c1fc..b1653c61127b 100644 --- a/internal/cocoa/api_cocoa_darwin.go +++ b/internal/cocoa/api_cocoa_darwin.go @@ -21,37 +21,50 @@ import ( ) var ( + class_NSInvocation = objc.GetClass("NSInvocation") + class_NSMethodSignature = objc.GetClass("NSMethodSignature") class_NSAutoreleasePool = objc.GetClass("NSAutoreleasePool") class_NSString = objc.GetClass("NSString") class_NSProcessInfo = objc.GetClass("NSProcessInfo") class_NSColor = objc.GetClass("NSColor") + class_NSWindow = objc.GetClass("NSWindow") + class_NSView = objc.GetClass("NSView") class_NSScreen = objc.GetClass("NSScreen") ) var ( - sel_alloc = objc.RegisterName("alloc") - sel_new = objc.RegisterName("new") - sel_release = objc.RegisterName("release") - sel_initWithUTF8String = objc.RegisterName("initWithUTF8String:") - sel_UTF8String = objc.RegisterName("UTF8String") - sel_length = objc.RegisterName("length") - sel_processInfo = objc.RegisterName("processInfo") - sel_frame = objc.RegisterName("frame") - sel_contentView = objc.RegisterName("contentView") - sel_setBackgroundColor = objc.RegisterName("setBackgroundColor:") - sel_colorWithSRGBRedGreenBlueAlpha = objc.RegisterName("colorWithSRGBRed:green:blue:alpha:") - sel_setFrameSize = objc.RegisterName("setFrameSize:") - sel_object = objc.RegisterName("object") - sel_styleMask = objc.RegisterName("styleMask") - sel_setStyleMask = objc.RegisterName("setStyleMask:") - sel_mainScreen = objc.RegisterName("mainScreen") - sel_screen = objc.RegisterName("screen") - sel_isVisible = objc.RegisterName("isVisible") - sel_deviceDescription = objc.RegisterName("deviceDescription") - sel_objectForKey = objc.RegisterName("objectForKey:") - sel_unsignedIntValue = objc.RegisterName("unsignedIntValue") - sel_setLayer = objc.RegisterName("setLayer:") - sel_setWantsLayer = objc.RegisterName("setWantsLayer:") + 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_invokeWithTarget = objc.RegisterName("invokeWithTarget:") + 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") + sel_processInfo = objc.RegisterName("processInfo") + sel_frame = objc.RegisterName("frame") + sel_contentView = objc.RegisterName("contentView") + sel_setBackgroundColor = objc.RegisterName("setBackgroundColor:") + sel_colorWithSRGBRedGreenBlueAlpha = objc.RegisterName("colorWithSRGBRed:green:blue:alpha:") + sel_setFrameSize = objc.RegisterName("setFrameSize:") + sel_object = objc.RegisterName("object") + sel_styleMask = objc.RegisterName("styleMask") + sel_setStyleMask = objc.RegisterName("setStyleMask:") + sel_mainScreen = objc.RegisterName("mainScreen") + sel_screen = objc.RegisterName("screen") + sel_isVisible = objc.RegisterName("isVisible") + sel_deviceDescription = objc.RegisterName("deviceDescription") + sel_objectForKey = objc.RegisterName("objectForKey:") + sel_unsignedIntValue = objc.RegisterName("unsignedIntValue") + sel_setLayer = objc.RegisterName("setLayer:") + sel_setWantsLayer = objc.RegisterName("setWantsLayer:") ) const ( @@ -163,6 +176,52 @@ func (v NSView) SetWantsLayer(wantsLayer bool) { v.Send(sel_setWantsLayer, wantsLayer) } +// 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 (i NSInvocation) SetSelector(cmd objc.SEL) { + i.Send(sel_setSelector, cmd) +} + +func (i NSInvocation) SetTarget(target objc.ID) { + i.Send(sel_setTarget, target) +} + +func (i NSInvocation) SetArgumentAtIndex(arg unsafe.Pointer, idx int) { + i.Send(sel_setArgumentAtIndex, arg, idx) +} + +func (i NSInvocation) GetReturnValue(ret unsafe.Pointer) { + i.Send(sel_getReturnValue, ret) +} + +func (i NSInvocation) Invoke() { + i.Send(sel_invoke) +} + +func (i NSInvocation) InvokeWithTarget(target objc.ID) { + i.Send(sel_invokeWithTarget, target) +} + +type NSMethodSignature struct { + objc.ID +} + +// 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 } diff --git a/internal/graphicsdriver/metal/mtl/mtl_darwin.go b/internal/graphicsdriver/metal/mtl/mtl_darwin.go index bd19ecf64f8e..abd49deccbd8 100644 --- a/internal/graphicsdriver/metal/mtl/mtl_darwin.go +++ b/internal/graphicsdriver/metal/mtl/mtl_darwin.go @@ -1003,10 +1003,20 @@ func (bce BlitCommandEncoder) SynchronizeTexture(texture Texture, slice int, lev // // Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400754-copyfromtexture?language=objc. func (bce BlitCommandEncoder) CopyFromTexture(sourceTexture Texture, sourceSlice int, sourceLevel int, sourceOrigin Origin, sourceSize Size, destinationTexture Texture, destinationSlice int, destinationLevel int, destinationOrigin Origin) { - sel := sel_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin - bce.commandEncoder.Send(sel, - sourceTexture.texture, sourceSlice, sourceLevel, sourceOrigin, sourceSize, - destinationTexture.texture, destinationSlice, destinationLevel, destinationOrigin) + // copyFromTexture requires so many arguments that Send doesn't work (#3135). + 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.