1/*
2 * Copyright 2021 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "experimental/graphite/src/mtl/MtlCaps.h"
9
10#include "experimental/graphite/include/TextureInfo.h"
11#include "experimental/graphite/include/mtl/MtlTypes.h"
12#include "experimental/graphite/src/mtl/MtlUtils.h"
13
14namespace skgpu::mtl {
15
16Caps::Caps(const id<MTLDevice> device)
17        : skgpu::Caps() {
18    // TODO: allocate shadercaps
19
20    this->initGPUFamily(device);
21    this->initCaps(device);
22    this->initShaderCaps();
23
24    this->initFormatTable();
25
26    // Metal-specific caps
27}
28
29// translates from older MTLFeatureSet interface to MTLGPUFamily interface
30bool Caps::GetGPUFamilyFromFeatureSet(id<MTLDevice> device, GPUFamily* gpuFamily, int* group) {
31#if defined(SK_BUILD_FOR_MAC)
32    // Apple Silicon is only available in later OSes
33    *gpuFamily = GPUFamily::kMac;
34    // Mac OSX 14
35    if (@available(macOS 10.14, *)) {
36        if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily2_v1]) {
37            *group = 2;
38            return true;
39        }
40        if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v4]) {
41            *group = 1;
42            return true;
43        }
44    }
45    // Mac OSX 13
46    if (@available(macOS 10.13, *)) {
47        if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v3]) {
48            *group = 1;
49            return true;
50        }
51    }
52    // Mac OSX 12
53    if (@available(macOS 10.12, *)) {
54        if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v2]) {
55            *group = 1;
56            return true;
57        }
58    }
59    // Mac OSX 11
60    if (@available(macOS 10.11, *)) {
61        if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
62            *group = 1;
63            return true;
64        }
65    }
66#elif defined(SK_BUILD_FOR_IOS)
67    // TODO: support tvOS
68   *gpuFamily = GPUFamily::kApple;
69    // iOS 12
70    if (@available(iOS 12.0, *)) {
71        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily5_v1]) {
72            *group = 5;
73            return true;
74        }
75        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v2]) {
76            *group = 4;
77            return true;
78        }
79        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v4]) {
80            *group = 3;
81            return true;
82        }
83        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v5]) {
84            *group = 2;
85            return true;
86        }
87        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v5]) {
88            *group = 1;
89            return true;
90        }
91    }
92    // iOS 11
93    if (@available(iOS 11.0, *)) {
94        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
95            *group = 4;
96            return true;
97        }
98        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v3]) {
99            *group = 3;
100            return true;
101        }
102        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v4]) {
103            *group = 2;
104            return true;
105        }
106        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v4]) {
107            *group = 1;
108            return true;
109        }
110    }
111    // iOS 10
112    if (@available(iOS 10.0, *)) {
113        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2]) {
114            *group = 3;
115            return true;
116        }
117        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v3]) {
118            *group = 2;
119            return true;
120        }
121        if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v3]) {
122            *group = 1;
123            return true;
124        }
125    }
126    // We don't support earlier OSes
127#endif
128
129    // No supported GPU families were found
130    return false;
131}
132
133bool Caps::GetGPUFamily(id<MTLDevice> device, GPUFamily* gpuFamily, int* group) {
134#if GR_METAL_SDK_VERSION >= 220
135    if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
136        // Apple Silicon
137#if GR_METAL_SDK_VERSION >= 230
138        if ([device supportsFamily:MTLGPUFamilyApple7]) {
139            *gpuFamily = GPUFamily::kApple;
140            *group = 7;
141            return true;
142        }
143#endif
144#ifdef SK_BUILD_FOR_IOS
145        if ([device supportsFamily:MTLGPUFamilyApple6]) {
146            *gpuFamily = GPUFamily::kApple;
147            *group = 6;
148            return true;
149        }
150        if ([device supportsFamily:MTLGPUFamilyApple5]) {
151            *gpuFamily = GPUFamily::kApple;
152            *group = 5;
153            return true;
154        }
155        if ([device supportsFamily:MTLGPUFamilyApple4]) {
156            *gpuFamily = GPUFamily::kApple;
157            *group = 4;
158            return true;
159        }
160        if ([device supportsFamily:MTLGPUFamilyApple3]) {
161            *gpuFamily = GPUFamily::kApple;
162            *group = 3;
163            return true;
164        }
165        if ([device supportsFamily:MTLGPUFamilyApple2]) {
166            *gpuFamily = GPUFamily::kApple;
167            *group = 2;
168            return true;
169        }
170        if ([device supportsFamily:MTLGPUFamilyApple1]) {
171            *gpuFamily = GPUFamily::kApple;
172            *group = 1;
173            return true;
174        }
175#endif
176
177        // Older Macs
178        // At the moment MacCatalyst families have the same features as Mac,
179        // so we treat them the same
180        if ([device supportsFamily:MTLGPUFamilyMac2] ||
181            [device supportsFamily:MTLGPUFamilyMacCatalyst2]) {
182            *gpuFamily = GPUFamily::kMac;
183            *group = 2;
184            return true;
185        }
186        if ([device supportsFamily:MTLGPUFamilyMac1] ||
187            [device supportsFamily:MTLGPUFamilyMacCatalyst1]) {
188            *gpuFamily = GPUFamily::kMac;
189            *group = 1;
190            return true;
191        }
192    }
193#endif
194
195    // No supported GPU families were found
196    return false;
197}
198
199void Caps::initGPUFamily(id<MTLDevice> device) {
200    if (!GetGPUFamily(device, &fGPUFamily, &fFamilyGroup) &&
201        !GetGPUFamilyFromFeatureSet(device, &fGPUFamily, &fFamilyGroup)) {
202        // We don't know what this is, fall back to minimum defaults
203#ifdef SK_BUILD_FOR_MAC
204        fGPUFamily = GPUFamily::kMac;
205        fFamilyGroup = 1;
206#else
207        fGPUFamily = GPUFamily::kApple;
208        fFamilyGroup = 1;
209#endif
210    }
211}
212
213void Caps::initCaps(const id<MTLDevice> device) {
214    // TODO
215}
216
217void Caps::initShaderCaps() {
218    // TODO
219}
220
221void Caps::initFormatTable() {
222    // TODO
223}
224
225skgpu::TextureInfo Caps::getDefaultSampledTextureInfo(SkColorType colorType,
226                                                      uint32_t levelCount,
227                                                      Protected,
228                                                      Renderable renderable) const {
229    MTLTextureUsage usage = MTLTextureUsageShaderRead;
230    if (renderable == Renderable::kYes) {
231        usage |= MTLTextureUsageRenderTarget;
232    }
233
234    TextureInfo info;
235    info.fSampleCount = 1;
236    info.fLevelCount = levelCount;
237    info.fFormat = SkColorTypeToFormat(colorType);
238    info.fUsage = usage;
239    info.fStorageMode = MTLStorageModePrivate;
240    info.fFramebufferOnly = false;
241
242    return info;
243}
244
245skgpu::TextureInfo Caps::getDefaultMSAATextureInfo(SkColorType colorType,
246                                                   uint32_t sampleCount,
247                                                   Protected) const {
248    MTLTextureUsage usage = MTLTextureUsageRenderTarget;
249
250    TextureInfo info;
251    info.fSampleCount = sampleCount;
252    info.fLevelCount = 1;
253    info.fFormat = SkColorTypeToFormat(colorType);
254    info.fUsage = usage;
255    info.fStorageMode = MTLStorageModePrivate;
256    info.fFramebufferOnly = false;
257
258    return info;
259}
260
261skgpu::TextureInfo Caps::getDefaultDepthStencilTextureInfo(DepthStencilType depthStencilType,
262                                                           uint32_t sampleCount,
263                                                           Protected) const {
264    TextureInfo info;
265    info.fSampleCount = sampleCount;
266    info.fLevelCount = 1;
267    info.fFormat = DepthStencilTypeToFormat(depthStencilType);
268    info.fUsage = MTLTextureUsageRenderTarget;
269    info.fStorageMode = MTLStorageModePrivate;
270    info.fFramebufferOnly = false;
271
272    return info;
273}
274
275
276
277
278} // namespace skgpu::mtl
279