diff --git a/internal/cocoa/api_cocoa_darwin.go b/internal/cocoa/api_cocoa_darwin.go index 859ac3c36..b1653c611 100644 --- a/internal/cocoa/api_cocoa_darwin.go +++ b/internal/cocoa/api_cocoa_darwin.go @@ -63,6 +63,8 @@ var ( 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 ( @@ -147,14 +149,7 @@ func (w NSWindow) Screen() NSScreen { } func (w NSWindow) Frame() NSRect { - sig := NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(class_NSWindow), sel_frame) - inv := NSInvocation_invocationWithMethodSignature(sig) - inv.SetTarget(w.ID) - inv.SetSelector(sel_frame) - inv.Invoke() - var rect NSRect - inv.GetReturnValue(unsafe.Pointer(&rect)) - return rect + return objc.Send[NSRect](w.ID, sel_frame) } func (w NSWindow) ContentView() NSView { @@ -166,29 +161,19 @@ type NSView struct { } func (v NSView) SetFrameSize(size CGSize) { - sig := NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(class_NSView), sel_setFrameSize) - inv := NSInvocation_invocationWithMethodSignature(sig) - inv.SetSelector(sel_setFrameSize) - inv.SetArgumentAtIndex(unsafe.Pointer(&size), 2) - inv.InvokeWithTarget(v.ID) + v.ID.Send(sel_setFrameSize, size) } func (v NSView) Frame() NSRect { - sig := NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(class_NSView), sel_frame) - inv := NSInvocation_invocationWithMethodSignature(sig) - inv.SetSelector(sel_frame) - inv.InvokeWithTarget(v.ID) - var rect NSRect - inv.GetReturnValue(unsafe.Pointer(&rect)) - return rect + return objc.Send[NSRect](v.ID, sel_frame) } func (v NSView) SetLayer(layer uintptr) { - v.Send(objc.RegisterName("setLayer:"), layer) + v.Send(sel_setLayer, layer) } func (v NSView) SetWantsLayer(wantsLayer bool) { - v.Send(objc.RegisterName("setWantsLayer:"), wantsLayer) + v.Send(sel_setWantsLayer, wantsLayer) } // NSInvocation is being used to call functions that can't be called directly with purego.SyscallN. @@ -229,10 +214,6 @@ 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. // diff --git a/internal/graphicsdriver/metal/ca/ca_darwin.go b/internal/graphicsdriver/metal/ca/ca_darwin.go index 2825368e2..e030377eb 100644 --- a/internal/graphicsdriver/metal/ca/ca_darwin.go +++ b/internal/graphicsdriver/metal/ca/ca_darwin.go @@ -33,6 +33,26 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl" ) +var class_CAMetalLayer = objc.GetClass("CAMetalLayer") + +var ( + sel_pixelFormat = objc.RegisterName("pixelFormat") + sel_setDevice = objc.RegisterName("setDevice:") + sel_setOpaque = objc.RegisterName("setOpaque:") + sel_setPixelFormat = objc.RegisterName("setPixelFormat:") + sel_new = objc.RegisterName("new") + sel_setColorspace = objc.RegisterName("setColorspace:") + sel_setMaximumDrawableCount = objc.RegisterName("setMaximumDrawableCount:") + sel_setDisplaySyncEnabled = objc.RegisterName("setDisplaySyncEnabled:") + sel_setDrawableSize = objc.RegisterName("setDrawableSize:") + sel_nextDrawable = objc.RegisterName("nextDrawable") + sel_presentsWithTransaction = objc.RegisterName("presentsWithTransaction") + sel_setPresentsWithTransaction = objc.RegisterName("setPresentsWithTransaction:") + sel_setFramebufferOnly = objc.RegisterName("setFramebufferOnly:") + sel_texture = objc.RegisterName("texture") + sel_present = objc.RegisterName("present") +) + // Layer is an object that manages image-based content and // allows you to perform animations on that content. // @@ -86,14 +106,14 @@ func NewMetalLayer(colorSpace graphicsdriver.ColorSpace) (MetalLayer, error) { colorSpaceSym = kCGColorSpaceDisplayP3 } - layer := objc.ID(objc.GetClass("CAMetalLayer")).Send(objc.RegisterName("new")) + layer := objc.ID(class_CAMetalLayer).Send(sel_new) // setColorspace: is available from iOS 13.0? // https://github.com/hajimehoshi/ebiten/commit/3af351a2aa31e30affd433429c42130015b302f3 // TODO: Enable this on iOS as well. if runtime.GOOS != "ios" { // Dlsym returns pointer to symbol so dereference it. colorspace, _, _ := purego.SyscallN(cgColorSpaceCreateWithName, **(**uintptr)(unsafe.Pointer(&colorSpaceSym))) - layer.Send(objc.RegisterName("setColorspace:"), colorspace) + layer.Send(sel_setColorspace, colorspace) purego.SyscallN(cgColorSpaceRelease, colorspace) } return MetalLayer{layer}, nil @@ -108,19 +128,19 @@ func (ml MetalLayer) Layer() unsafe.Pointer { // // Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat?language=objc. func (ml MetalLayer) PixelFormat() mtl.PixelFormat { - return mtl.PixelFormat(ml.metalLayer.Send(objc.RegisterName("pixelFormat"))) + return mtl.PixelFormat(ml.metalLayer.Send(sel_pixelFormat)) } // SetDevice sets the Metal device responsible for the layer's drawable resources. // // Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478163-device?language=objc. func (ml MetalLayer) SetDevice(device mtl.Device) { - ml.metalLayer.Send(objc.RegisterName("setDevice:"), uintptr(device.Device())) + ml.metalLayer.Send(sel_setDevice, uintptr(device.Device())) } // SetOpaque a Boolean value indicating whether the layer contains completely opaque content. func (ml MetalLayer) SetOpaque(opaque bool) { - ml.metalLayer.Send(objc.RegisterName("setOpaque:"), opaque) + ml.metalLayer.Send(sel_setOpaque, opaque) } // SetPixelFormat controls the pixel format of textures for rendering layer content. @@ -136,7 +156,7 @@ func (ml MetalLayer) SetPixelFormat(pf mtl.PixelFormat) { default: panic(errors.New(fmt.Sprintf("invalid pixel format %d", pf))) } - ml.metalLayer.Send(objc.RegisterName("setPixelFormat:"), uint(pf)) + ml.metalLayer.Send(sel_setPixelFormat, uint(pf)) } // SetMaximumDrawableCount controls the number of Metal drawables in the resource pool @@ -149,7 +169,7 @@ func (ml MetalLayer) SetMaximumDrawableCount(count int) { 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) + ml.metalLayer.Send(sel_setMaximumDrawableCount, count) } // SetDisplaySyncEnabled controls whether the Metal layer and its drawables @@ -160,28 +180,21 @@ func (ml MetalLayer) SetDisplaySyncEnabled(enabled bool) { if runtime.GOOS == "ios" { return } - ml.metalLayer.Send(objc.RegisterName("setDisplaySyncEnabled:"), enabled) + ml.metalLayer.Send(sel_setDisplaySyncEnabled, enabled) } // SetDrawableSize sets the size, in pixels, of textures for rendering layer content. // // Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478174-drawablesize?language=objc. func (ml MetalLayer) SetDrawableSize(width, height int) { - // 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() + ml.metalLayer.Send(sel_setDrawableSize, cocoa.CGSize{Width: cocoa.CGFloat(width), Height: cocoa.CGFloat(height)}) } // NextDrawable returns a Metal drawable. // // Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478172-nextdrawable?language=objc. func (ml MetalLayer) NextDrawable() (MetalDrawable, error) { - md := ml.metalLayer.Send(objc.RegisterName("nextDrawable")) + md := ml.metalLayer.Send(sel_nextDrawable) if md == 0 { return MetalDrawable{}, errors.New("nextDrawable returned nil") } @@ -192,21 +205,21 @@ func (ml MetalLayer) NextDrawable() (MetalDrawable, error) { // // Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction?language=objc func (ml MetalLayer) PresentsWithTransaction() bool { - return ml.metalLayer.Send(objc.RegisterName("presentsWithTransaction")) != 0 + return ml.metalLayer.Send(sel_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?language=objc func (ml MetalLayer) SetPresentsWithTransaction(presentsWithTransaction bool) { - ml.metalLayer.Send(objc.RegisterName("setPresentsWithTransaction:"), presentsWithTransaction) + ml.metalLayer.Send(sel_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?language=objc func (ml MetalLayer) SetFramebufferOnly(framebufferOnly bool) { - ml.metalLayer.Send(objc.RegisterName("setFramebufferOnly:"), framebufferOnly) + ml.metalLayer.Send(sel_setFramebufferOnly, framebufferOnly) } // MetalDrawable is a displayable resource that can be rendered or written to by Metal. @@ -225,12 +238,12 @@ func (md MetalDrawable) Drawable() unsafe.Pointer { // // Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable/1478159-texture?language=objc. func (md MetalDrawable) Texture() mtl.Texture { - return mtl.NewTexture(md.metalDrawable.Send(objc.RegisterName("texture"))) + return mtl.NewTexture(md.metalDrawable.Send(sel_texture)) } // Present presents the drawable onscreen as soon as possible. // // Reference: https://developer.apple.com/documentation/metal/mtldrawable/1470284-present?language=objc. func (md MetalDrawable) Present() { - md.metalDrawable.Send(objc.RegisterName("present")) + md.metalDrawable.Send(sel_present) } diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 0e4660e82..cbfc9bc4a 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -32,6 +32,8 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/shaderir" ) +var sel_supportsFamily = objc.RegisterName("supportsFamily:") + type Graphics struct { view view @@ -709,7 +711,7 @@ func (g *Graphics) MaxImageSize() int { // supportsFamily is available as of macOS 10.15+ and iOS 13.0+. // https://developer.apple.com/documentation/metal/mtldevice/3143473-supportsfamily - if d.RespondsToSelector(objc.RegisterName("supportsFamily:")) { + if d.RespondsToSelector(sel_supportsFamily) { // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf g.maxImageSize = 8192 switch { diff --git a/internal/graphicsdriver/metal/mtl/mtl_darwin.go b/internal/graphicsdriver/metal/mtl/mtl_darwin.go index 85da17128..e119e556b 100644 --- a/internal/graphicsdriver/metal/mtl/mtl_darwin.go +++ b/internal/graphicsdriver/metal/mtl/mtl_darwin.go @@ -484,7 +484,6 @@ var ( ) var ( - sel_class = objc.RegisterName("class") sel_length = objc.RegisterName("length") sel_isHeadless = objc.RegisterName("isHeadless") sel_isLowPower = objc.RegisterName("isLowPower") @@ -853,12 +852,7 @@ func (cb CommandBuffer) RenderCommandEncoderWithDescriptor(rpd RenderPassDescrip 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() + colorAttachments0.Send(sel_setClearColor, rpd.ColorAttachments[0].ClearColor) var stencilAttachment = renderPassDescriptor.Send(sel_stencilAttachment) stencilAttachment.Send(sel_setLoadAction, int(rpd.StencilAttachment.LoadAction)) stencilAttachment.Send(sel_setStoreAction, int(rpd.StencilAttachment.StoreAction)) @@ -912,11 +906,7 @@ func (rce RenderCommandEncoder) SetRenderPipelineState(rps RenderPipelineState) } func (rce RenderCommandEncoder) SetViewport(viewport Viewport) { - 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() + rce.commandEncoder.Send(sel_setViewport, viewport) } // SetScissorRect sets the scissor rectangle for a fragment scissor test. diff --git a/internal/ui/ui_darwin.go b/internal/ui/ui_darwin.go index cce7d41de..f773e12fa 100644 --- a/internal/ui/ui_darwin.go +++ b/internal/ui/ui_darwin.go @@ -20,7 +20,6 @@ import ( "errors" "fmt" "reflect" - "unsafe" "github.com/ebitengine/purego/objc" @@ -257,13 +256,7 @@ var ( ) func currentMouseLocation() (x, y int) { - sig := cocoa.NSMethodSignature_signatureWithObjCTypes("{NSPoint=dd}@:") - inv := cocoa.NSInvocation_invocationWithMethodSignature(sig) - inv.SetTarget(objc.ID(class_NSEvent)) - inv.SetSelector(sel_mouseLocation) - inv.Invoke() - var point cocoa.NSPoint - inv.GetReturnValue(unsafe.Pointer(&point)) + point := objc.Send[cocoa.NSPoint](objc.ID(class_NSEvent), sel_mouseLocation) x, y = int(point.X), int(point.Y)