diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index f1cce0fc1..9cb9100d8 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -22,6 +22,8 @@ import ( "time" "unsafe" + "github.com/ebitengine/purego/objc" + "github.com/hajimehoshi/ebiten/v2/internal/cocoa" "github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" @@ -680,13 +682,46 @@ func (g *Graphics) MaxImageSize() int { return g.maxImageSize } - // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf - g.maxImageSize = 8192 + d := g.view.getMTLDevice() + + // 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:")) { + // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf + g.maxImageSize = 8192 + switch { + case d.SupportsFamily(mtl.GPUFamilyApple3): + g.maxImageSize = 16384 + case d.SupportsFamily(mtl.GPUFamilyMac2): + g.maxImageSize = 16384 + } + return g.maxImageSize + } + + // supportsFeatureSet is deprecated but some old macOS/iOS versions only supports this (#2553). switch { - case g.view.getMTLDevice().SupportsFamily(mtl.GPUFamilyApple3): + case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily5_v1): g.maxImageSize = 16384 - case g.view.getMTLDevice().SupportsFamily(mtl.GPUFamilyMac2): + case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily4_v1): g.maxImageSize = 16384 + case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily3_v1): + g.maxImageSize = 16384 + case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily2_v2): + g.maxImageSize = 8192 + case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily2_v1): + g.maxImageSize = 4096 + case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily1_v2): + g.maxImageSize = 8192 + case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily1_v1): + g.maxImageSize = 4096 + case d.SupportsFeatureSet(mtl.FeatureSet_tvOS_GPUFamily2_v1): + g.maxImageSize = 16384 + case d.SupportsFeatureSet(mtl.FeatureSet_tvOS_GPUFamily1_v1): + g.maxImageSize = 8192 + case d.SupportsFeatureSet(mtl.FeatureSet_macOS_GPUFamily1_v1): + g.maxImageSize = 16384 + default: + panic("metal: there is no supported feature set") } return g.maxImageSize } diff --git a/internal/graphicsdriver/metal/mtl/mtl_darwin.go b/internal/graphicsdriver/metal/mtl/mtl_darwin.go index e42f51601..ea2ca5eda 100644 --- a/internal/graphicsdriver/metal/mtl/mtl_darwin.go +++ b/internal/graphicsdriver/metal/mtl/mtl_darwin.go @@ -52,6 +52,43 @@ const ( GPUFamilyMac2 GPUFamily = 2002 ) +// FeatureSet defines a specific platform, hardware, and software configuration. +// +// Reference: https://developer.apple.com/documentation/metal/mtlfeatureset. +type FeatureSet uint16 + +const ( + FeatureSet_iOS_GPUFamily1_v1 FeatureSet = 0 + FeatureSet_iOS_GPUFamily1_v2 FeatureSet = 2 + FeatureSet_iOS_GPUFamily1_v3 FeatureSet = 5 + FeatureSet_iOS_GPUFamily1_v4 FeatureSet = 8 + FeatureSet_iOS_GPUFamily1_v5 FeatureSet = 12 + FeatureSet_iOS_GPUFamily2_v1 FeatureSet = 1 + FeatureSet_iOS_GPUFamily2_v2 FeatureSet = 3 + FeatureSet_iOS_GPUFamily2_v3 FeatureSet = 6 + FeatureSet_iOS_GPUFamily2_v4 FeatureSet = 9 + FeatureSet_iOS_GPUFamily2_v5 FeatureSet = 13 + FeatureSet_iOS_GPUFamily3_v1 FeatureSet = 4 + FeatureSet_iOS_GPUFamily3_v2 FeatureSet = 7 + FeatureSet_iOS_GPUFamily3_v3 FeatureSet = 10 + FeatureSet_iOS_GPUFamily3_v4 FeatureSet = 14 + FeatureSet_iOS_GPUFamily4_v1 FeatureSet = 11 + FeatureSet_iOS_GPUFamily4_v2 FeatureSet = 15 + FeatureSet_iOS_GPUFamily5_v1 FeatureSet = 16 + FeatureSet_tvOS_GPUFamily1_v1 FeatureSet = 30000 + FeatureSet_tvOS_GPUFamily1_v2 FeatureSet = 30001 + FeatureSet_tvOS_GPUFamily1_v3 FeatureSet = 30002 + FeatureSet_tvOS_GPUFamily1_v4 FeatureSet = 30004 + FeatureSet_tvOS_GPUFamily2_v1 FeatureSet = 30003 + FeatureSet_tvOS_GPUFamily2_v2 FeatureSet = 30005 + FeatureSet_macOS_GPUFamily1_v1 FeatureSet = 10000 + FeatureSet_macOS_GPUFamily1_v2 FeatureSet = 10001 + FeatureSet_macOS_GPUFamily1_v3 FeatureSet = 10003 + FeatureSet_macOS_GPUFamily1_v4 FeatureSet = 10004 + FeatureSet_macOS_GPUFamily2_v1 FeatureSet = 10005 + FeatureSet_macOS_ReadWriteTextureTier2 FeatureSet = 10002 +) + // TextureType defines The dimension of each image, including whether multiple images are arranged into an array or // a cube. // @@ -458,6 +495,7 @@ var ( sel_isLowPower = objc.RegisterName("isLowPower") sel_name = objc.RegisterName("name") sel_supportsFamily = objc.RegisterName("supportsFamily:") + sel_supportsFeatureSet = objc.RegisterName("supportsFeatureSet:") sel_newCommandQueue = objc.RegisterName("newCommandQueue") sel_newLibraryWithSource_options_error = objc.RegisterName("newLibraryWithSource:options:error:") sel_release = objc.RegisterName("release") @@ -529,6 +567,7 @@ var ( 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:") + sel_respondsToSelector = objc.RegisterName("respondsToSelector:") ) // CreateSystemDefaultDevice returns the preferred system default Metal device. @@ -561,6 +600,13 @@ func CreateSystemDefaultDevice() (Device, bool) { // Device returns the underlying id pointer. func (d Device) Device() unsafe.Pointer { return *(*unsafe.Pointer)(unsafe.Pointer(&d.device)) } +// RespondsToSelector returns a Boolean value that indicates whether the receiver implements or inherits a method that can respond to a specified message. +// +// Reference: https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418583-respondstoselector +func (d Device) RespondsToSelector(sel objc.SEL) bool { + return d.device.Send(sel_respondsToSelector, sel) != 0 +} + // SupportsFamily returns a Boolean value that indicates whether the GPU device supports the feature set of a specific GPU family. // // Reference: https://developer.apple.com/documentation/metal/mtldevice/3143473-supportsfamily @@ -568,6 +614,13 @@ func (d Device) SupportsFamily(gpuFamily GPUFamily) bool { return d.device.Send(sel_supportsFamily, uintptr(gpuFamily)) != 0 } +// 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 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.