• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/gpu/graphite/mtl/MtlCaps.h"
9
10#include "include/core/SkTextureCompressionType.h"
11#include "include/gpu/graphite/TextureInfo.h"
12#include "include/gpu/graphite/mtl/MtlGraphiteTypes.h"
13#include "include/gpu/graphite/mtl/MtlGraphiteTypesUtils.h"
14#include "src/gpu/SwizzlePriv.h"
15#include "src/gpu/graphite/CommandBuffer.h"
16#include "src/gpu/graphite/ComputePipelineDesc.h"
17#include "src/gpu/graphite/GraphicsPipelineDesc.h"
18#include "src/gpu/graphite/GraphiteResourceKey.h"
19#include "src/gpu/graphite/RenderPassDesc.h"
20#include "src/gpu/graphite/RendererProvider.h"
21#include "src/gpu/graphite/TextureProxy.h"
22#include "src/gpu/graphite/mtl/MtlGraphicsPipeline.h"
23#include "src/gpu/graphite/mtl/MtlGraphiteTypesPriv.h"
24#include "src/gpu/graphite/mtl/MtlGraphiteUtilsPriv.h"
25#include "src/gpu/mtl/MtlUtilsPriv.h"
26#include "src/sksl/SkSLUtil.h"
27
28namespace skgpu::graphite {
29
30MtlCaps::MtlCaps(const id<MTLDevice> device, const ContextOptions& options)
31        : Caps() {
32    this->initGPUFamily(device);
33    this->initCaps(device);
34    this->initShaderCaps();
35
36    this->initFormatTable(device);
37
38    // Metal-specific MtlCaps
39
40    this->finishInitialization(options);
41}
42
43bool MtlCaps::GetGPUFamily(id<MTLDevice> device, GPUFamily* gpuFamily, int* group) {
44#if SKGPU_GRAPHITE_METAL_SDK_VERSION >= 220
45    if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
46        // Apple Silicon
47#if SKGPU_GRAPHITE_METAL_SDK_VERSION >= 230
48        if ([device supportsFamily:MTLGPUFamilyApple7]) {
49            *gpuFamily = GPUFamily::kApple;
50            *group = 7;
51            return true;
52        }
53#endif
54#ifdef SK_BUILD_FOR_IOS
55        if ([device supportsFamily:MTLGPUFamilyApple6]) {
56            *gpuFamily = GPUFamily::kApple;
57            *group = 6;
58            return true;
59        }
60        if ([device supportsFamily:MTLGPUFamilyApple5]) {
61            *gpuFamily = GPUFamily::kApple;
62            *group = 5;
63            return true;
64        }
65        if ([device supportsFamily:MTLGPUFamilyApple4]) {
66            *gpuFamily = GPUFamily::kApple;
67            *group = 4;
68            return true;
69        }
70        if ([device supportsFamily:MTLGPUFamilyApple3]) {
71            *gpuFamily = GPUFamily::kApple;
72            *group = 3;
73            return true;
74        }
75        if ([device supportsFamily:MTLGPUFamilyApple2]) {
76            *gpuFamily = GPUFamily::kApple;
77            *group = 2;
78            return true;
79        }
80        if ([device supportsFamily:MTLGPUFamilyApple1]) {
81            *gpuFamily = GPUFamily::kApple;
82            *group = 1;
83            return true;
84        }
85#endif
86
87        // Older Macs
88        // MTLGPUFamilyMac1, MTLGPUFamilyMacCatalyst1, and MTLGPUFamilyMacCatalyst2 are deprecated.
89        // However, some MTLGPUFamilyMac1 only hardware is still supported.
90        // MacCatalyst families have the same features as Mac, so treat them the same
91        if ([device supportsFamily:MTLGPUFamilyMac2] ||
92            [device supportsFamily:(MTLGPUFamily)4002/*MTLGPUFamilyMacCatalyst2*/]) {
93            *gpuFamily = GPUFamily::kMac;
94            *group = 2;
95            return true;
96        }
97        if ([device supportsFamily:(MTLGPUFamily)2001/*MTLGPUFamilyMac1*/] ||
98            [device supportsFamily:(MTLGPUFamily)4001/*MTLGPUFamilyMacCatalyst1*/]) {
99            *gpuFamily = GPUFamily::kMac;
100            *group = 1;
101            return true;
102        }
103    }
104#endif
105
106    // No supported GPU families were found
107    return false;
108}
109
110void MtlCaps::initGPUFamily(id<MTLDevice> device) {
111    if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
112        if (GetGPUFamily(device, &fGPUFamily, &fFamilyGroup)) {
113            return;
114        }
115    }
116
117    // We don't know what this is, fall back to minimum defaults
118#ifdef SK_BUILD_FOR_MAC
119    fGPUFamily = GPUFamily::kMac;
120    fFamilyGroup = 1;
121#else
122    fGPUFamily = GPUFamily::kApple;
123    fFamilyGroup = 1;
124#endif
125}
126
127void MtlCaps::initCaps(const id<MTLDevice> device) {
128#if defined(GPU_TEST_UTILS)
129    this->setDeviceName([[device name] UTF8String]);
130#endif
131
132    if (this->isMac() || fFamilyGroup >= 3) {
133        fMaxTextureSize = 16384;
134    } else {
135        fMaxTextureSize = 8192;
136    }
137
138    // We use constant address space for our uniform buffers which has various alignment
139    // requirements for the offset when binding the buffer. On MacOS Intel the offset must align
140    // to 256. On iOS or Apple Silicon we must align to the max of the data type consumed by the
141    // vertex function or 4 bytes, or we can ignore the data type and just use 16 bytes.
142    //
143    // On Mac, all copies must be aligned to at least 4 bytes; on iOS there is no alignment.
144    if (this->isMac()) {
145        fRequiredUniformBufferAlignment = 256;
146        fRequiredTransferBufferAlignment = 4;
147    } else {
148        fRequiredUniformBufferAlignment = 16;
149        fRequiredTransferBufferAlignment = 1;
150    }
151
152    fResourceBindingReqs.fUniformBufferLayout = Layout::kMetal;
153    fResourceBindingReqs.fStorageBufferLayout = Layout::kMetal;
154    fResourceBindingReqs.fDistinctIndexRanges = true;
155
156    fResourceBindingReqs.fIntrinsicBufferBinding =
157            MtlGraphicsPipeline::kIntrinsicUniformBufferIndex;
158    fResourceBindingReqs.fRenderStepBufferBinding =
159            MtlGraphicsPipeline::kRenderStepUniformBufferIndex;
160    fResourceBindingReqs.fPaintParamsBufferBinding = MtlGraphicsPipeline::kPaintUniformBufferIndex;
161    fResourceBindingReqs.fGradientBufferBinding = MtlGraphicsPipeline::kGradientBufferIndex;
162
163    // Metal does not distinguish between uniform and storage buffers.
164    fRequiredStorageBufferAlignment = fRequiredUniformBufferAlignment;
165
166    fStorageBufferSupport = true;
167
168    fComputeSupport = true;
169
170    if (@available(macOS 10.12, iOS 14.0, tvOS 14.0, *)) {
171        fClampToBorderSupport = (this->isMac() || fFamilyGroup >= 7);
172    } else {
173        fClampToBorderSupport = false;
174    }
175
176    // Init sample counts. All devices support 1 (i.e. 0 in skia).
177    fColorSampleCounts.push_back(1);
178    if (![device.name containsString:@"Intel"]) {
179        if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) {
180            for (auto sampleCnt : {2, 4, 8}) {
181                if ([device supportsTextureSampleCount:sampleCnt]) {
182                    fColorSampleCounts.push_back(sampleCnt);
183                }
184            }
185        }
186    }
187}
188
189void MtlCaps::initShaderCaps() {
190    SkSL::ShaderCaps* shaderCaps = fShaderCaps.get();
191
192    // Dual source blending requires Metal 1.2.
193    if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) {
194        shaderCaps->fDualSourceBlendingSupport = true;
195    }
196
197    // Setting this true with the assumption that this cap will eventually mean we support varying
198    // precisions and not just via modifiers.
199    shaderCaps->fUsesPrecisionModifiers = true;
200    shaderCaps->fFlatInterpolationSupport = true;
201
202    shaderCaps->fShaderDerivativeSupport = true;
203    shaderCaps->fInfinitySupport = true;
204
205    if (@available(macOS 11.0, *)) {
206        if (this->isApple()) {
207            shaderCaps->fFBFetchSupport = true;
208            shaderCaps->fFBFetchColorName = "sk_LastFragColor";
209        }
210    }
211
212    shaderCaps->fIntegerSupport = true;
213    shaderCaps->fNonsquareMatrixSupport = true;
214    shaderCaps->fInverseHyperbolicSupport = true;
215
216    // Metal uses IEEE floats so assuming those values here.
217    shaderCaps->fFloatIs32Bits = true;
218}
219
220// Define this so we can use it to initialize arrays and work around
221// the fact that these pixel formats are not always available.
222#define kMTLPixelFormatB5G6R5Unorm MTLPixelFormat(40)
223#define kMTLPixelFormatABGR4Unorm MTLPixelFormat(42)
224#define kMTLPixelFormatETC2_RGB8 MTLPixelFormat(180)
225
226// These are all the valid MTLPixelFormats that we currently support in Skia.  They are roughly
227// ordered from most frequently used to least to improve look up times in arrays.
228static constexpr MTLPixelFormat kMtlFormats[] = {
229    MTLPixelFormatRGBA8Unorm,
230    MTLPixelFormatR8Unorm,
231    MTLPixelFormatA8Unorm,
232    MTLPixelFormatBGRA8Unorm,
233    kMTLPixelFormatB5G6R5Unorm,
234    MTLPixelFormatRGBA16Float,
235    MTLPixelFormatR16Float,
236    MTLPixelFormatRG8Unorm,
237    MTLPixelFormatRGB10A2Unorm,
238    // MTLPixelFormatBGR10A2Unorm
239    kMTLPixelFormatABGR4Unorm,
240    MTLPixelFormatRGBA8Unorm_sRGB,
241    MTLPixelFormatR16Unorm,
242    MTLPixelFormatRG16Unorm,
243    kMTLPixelFormatETC2_RGB8,
244#ifdef SK_BUILD_FOR_MAC
245    MTLPixelFormatBC1_RGBA,
246#endif
247    MTLPixelFormatRGBA16Unorm,
248    MTLPixelFormatRG16Float,
249
250    MTLPixelFormatStencil8,
251    MTLPixelFormatDepth16Unorm,
252    MTLPixelFormatDepth32Float,
253#ifdef SK_BUILD_FOR_MAC
254    MTLPixelFormatDepth24Unorm_Stencil8,
255#endif
256    MTLPixelFormatDepth32Float_Stencil8,
257
258    MTLPixelFormatInvalid,
259};
260
261void MtlCaps::setColorType(SkColorType colorType, std::initializer_list<MTLPixelFormat> formats) {
262    int idx = static_cast<int>(colorType);
263    for (auto it = formats.begin(); it != formats.end(); ++it) {
264        const auto& info = this->getFormatInfo(*it);
265        for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
266            if (info.fColorTypeInfos[i].fColorType == colorType) {
267                fColorTypeToFormatTable[idx] = *it;
268                return;
269            }
270        }
271    }
272}
273
274size_t MtlCaps::GetFormatIndex(MTLPixelFormat pixelFormat) {
275    static_assert(std::size(kMtlFormats) == MtlCaps::kNumMtlFormats,
276                  "Size of kMtlFormats array must match static value in header");
277    for (size_t i = 0; i < MtlCaps::kNumMtlFormats; ++i) {
278        if (kMtlFormats[i] == pixelFormat) {
279            return i;
280        }
281    }
282    return GetFormatIndex(MTLPixelFormatInvalid);
283}
284
285void MtlCaps::initFormatTable(const id<MTLDevice> device) {
286    FormatInfo* info;
287
288    if (@available(macOS 11.0, iOS 8.0, tvOS 9.0, *)) {
289        if (this->isApple()) {
290            SkASSERT(kMTLPixelFormatB5G6R5Unorm == MTLPixelFormatB5G6R5Unorm);
291            SkASSERT(kMTLPixelFormatABGR4Unorm == MTLPixelFormatABGR4Unorm);
292        }
293    }
294
295    // Format: RGBA8Unorm
296    {
297        info = &fFormatTable[GetFormatIndex(MTLPixelFormatRGBA8Unorm)];
298        info->fFlags = FormatInfo::kAllFlags;
299        info->fColorTypeInfoCount = 2;
300        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
301        int ctIdx = 0;
302        // Format: RGBA8Unorm, Surface: kRGBA_8888
303        {
304            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
305            ctInfo.fColorType = kRGBA_8888_SkColorType;
306            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
307        }
308        // Format: RGBA8Unorm, Surface: kRGB_888x
309        {
310            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
311            ctInfo.fColorType = kRGB_888x_SkColorType;
312            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
313            ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
314        }
315    }
316
317    // Format: R8Unorm
318    {
319        info = &fFormatTable[GetFormatIndex(MTLPixelFormatR8Unorm)];
320        info->fFlags = FormatInfo::kAllFlags;
321        info->fColorTypeInfoCount = 3;
322        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
323        int ctIdx = 0;
324        // Format: R8Unorm, Surface: kR8_unorm
325        {
326            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
327            ctInfo.fColorType = kR8_unorm_SkColorType;
328            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
329        }
330        // Format: R8Unorm, Surface: kAlpha_8
331        {
332            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
333            ctInfo.fColorType = kAlpha_8_SkColorType;
334            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
335            ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
336            ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
337        }
338        // Format: R8Unorm, Surface: kGray_8
339        {
340            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
341            ctInfo.fColorType = kGray_8_SkColorType;
342            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
343            ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
344        }
345    }
346
347    // Format: A8Unorm
348    {
349        info = &fFormatTable[GetFormatIndex(MTLPixelFormatA8Unorm)];
350        info->fFlags = FormatInfo::kTexturable_Flag;
351        info->fColorTypeInfoCount = 1;
352        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
353        int ctIdx = 0;
354        // Format: A8Unorm, Surface: kAlpha_8
355        {
356            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
357            ctInfo.fColorType = kAlpha_8_SkColorType;
358            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
359        }
360    }
361
362    // Format: BGRA8Unorm
363    {
364        info = &fFormatTable[GetFormatIndex(MTLPixelFormatBGRA8Unorm)];
365        info->fFlags = FormatInfo::kAllFlags;
366        info->fColorTypeInfoCount = 1;
367        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
368        int ctIdx = 0;
369        // Format: BGRA8Unorm, Surface: kBGRA_8888
370        {
371            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
372            ctInfo.fColorType = kBGRA_8888_SkColorType;
373            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
374        }
375    }
376
377    if (@available(macOS 11.0, iOS 8.0, tvOS 9.0, *)) {
378        if (this->isApple()) {
379            // Format: B5G6R5Unorm
380            {
381                info = &fFormatTable[GetFormatIndex(MTLPixelFormatB5G6R5Unorm)];
382                info->fFlags = FormatInfo::kAllFlags;
383                info->fColorTypeInfoCount = 1;
384                info->fColorTypeInfos =
385                        std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
386                int ctIdx = 0;
387                // Format: B5G6R5Unorm, Surface: kBGR_565
388                {
389                    auto& ctInfo = info->fColorTypeInfos[ctIdx++];
390                    ctInfo.fColorType = kRGB_565_SkColorType;
391                    ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag |
392                                    ColorTypeInfo::kRenderable_Flag;
393                }
394            }
395
396            // Format: ABGR4Unorm
397            {
398                info = &fFormatTable[GetFormatIndex(MTLPixelFormatABGR4Unorm)];
399                info->fFlags = FormatInfo::kAllFlags;
400                info->fColorTypeInfoCount = 1;
401                info->fColorTypeInfos =
402                        std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
403                int ctIdx = 0;
404                // Format: ABGR4Unorm, Surface: kABGR_4444
405                {
406                    auto& ctInfo = info->fColorTypeInfos[ctIdx++];
407                    ctInfo.fColorType = kARGB_4444_SkColorType;
408                    ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag |
409                                    ColorTypeInfo::kRenderable_Flag;
410                }
411            }
412        }
413    }
414
415    // Format: RGBA8Unorm_sRGB
416    {
417        info = &fFormatTable[GetFormatIndex(MTLPixelFormatRGBA8Unorm_sRGB)];
418        info->fFlags = FormatInfo::kAllFlags;
419        info->fColorTypeInfoCount = 1;
420        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
421        int ctIdx = 0;
422        // Format: RGBA8Unorm_sRGB, Surface: kSRGBA_8888
423        {
424            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
425            ctInfo.fColorType = kSRGBA_8888_SkColorType;
426            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
427        }
428    }
429
430    // Format: RGB10A2Unorm
431    {
432        info = &fFormatTable[GetFormatIndex(MTLPixelFormatRGB10A2Unorm)];
433        if (this->isMac() || fFamilyGroup >= 3) {
434            info->fFlags = FormatInfo::kAllFlags;
435        } else {
436            info->fFlags = FormatInfo::kTexturable_Flag;
437        }
438        info->fColorTypeInfoCount = 2;
439        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
440        int ctIdx = 0;
441        // Format: RGB10A2Unorm, Surface: kRGBA_1010102
442        {
443            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
444            ctInfo.fColorType = kRGBA_1010102_SkColorType;
445            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
446        }
447        // Format: RGB10A2Unorm, Surface: kRGB_101010x
448        {
449            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
450            ctInfo.fColorType = kRGB_101010x_SkColorType;
451            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
452            ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
453        }
454    }
455
456    // Format: RGBA16Float
457    {
458        info = &fFormatTable[GetFormatIndex(MTLPixelFormatRGBA16Float)];
459        info->fFlags = FormatInfo::kAllFlags;
460        info->fColorTypeInfoCount = 3;
461        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
462        int ctIdx = 0;
463        // Format: RGBA16Float, Surface: RGBA_F16
464        {
465            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
466            ctInfo.fColorType = kRGBA_F16_SkColorType;
467            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
468        }
469        // Format: RGBA16Float, Surface: RGBA_F16Norm
470        {
471            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
472            ctInfo.fColorType = kRGBA_F16Norm_SkColorType;
473            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
474        }
475        // Format: RGBA16Float, Surface: RGB_F16F16F16x
476        {
477            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
478            ctInfo.fColorType = kRGBA_F16_SkColorType;
479            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
480            ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
481        }
482    }
483
484    // Format: R16Float
485    {
486        info = &fFormatTable[GetFormatIndex(MTLPixelFormatR16Float)];
487        info->fFlags = FormatInfo::kAllFlags;
488        info->fColorTypeInfoCount = 1;
489        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
490        int ctIdx = 0;
491        // Format: R16Float, Surface: kA16_float
492        {
493            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
494            ctInfo.fColorType = kA16_float_SkColorType;
495            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
496            ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
497            ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
498        }
499    }
500
501    // Format: RG8Unorm
502    {
503        info = &fFormatTable[GetFormatIndex(MTLPixelFormatRG8Unorm)];
504        info->fFlags = FormatInfo::kAllFlags;
505        info->fColorTypeInfoCount = 1;
506        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
507        int ctIdx = 0;
508        // Format: RG8Unorm, Surface: kR8G8_unorm
509        {
510            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
511            ctInfo.fColorType = kR8G8_unorm_SkColorType;
512            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
513        }
514    }
515
516    // Format: RGBA16Unorm
517    {
518        info = &fFormatTable[GetFormatIndex(MTLPixelFormatRGBA16Unorm)];
519        if (this->isMac()) {
520            info->fFlags = FormatInfo::kAllFlags;
521        } else {
522            info->fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kRenderable_Flag;
523        }
524        info->fColorTypeInfoCount = 1;
525        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
526        int ctIdx = 0;
527        // Format: RGBA16Unorm, Surface: kR16G16B16A16_unorm
528        {
529            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
530            ctInfo.fColorType = kR16G16B16A16_unorm_SkColorType;
531            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
532        }
533    }
534
535    // Format: RG16Float
536    {
537        info = &fFormatTable[GetFormatIndex(MTLPixelFormatRG16Float)];
538        info->fFlags = FormatInfo::kAllFlags;
539        info->fColorTypeInfoCount = 1;
540        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
541        int ctIdx = 0;
542        // Format: RG16Float, Surface: kR16G16_float
543        {
544            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
545            ctInfo.fColorType = kR16G16_float_SkColorType;
546            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
547        }
548    }
549
550    // Format: R16Unorm
551    {
552        info = &fFormatTable[GetFormatIndex(MTLPixelFormatR16Unorm)];
553        if (this->isMac()) {
554            info->fFlags = FormatInfo::kAllFlags;
555        } else {
556            info->fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kRenderable_Flag;
557        }
558        info->fColorTypeInfoCount = 1;
559        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
560        int ctIdx = 0;
561        // Format: R16Unorm, Surface: kA16_unorm
562        {
563            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
564            ctInfo.fColorType = kA16_unorm_SkColorType;
565            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
566            ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
567            ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
568        }
569    }
570
571    // Format: RG16Unorm
572    {
573        info = &fFormatTable[GetFormatIndex(MTLPixelFormatRG16Unorm)];
574        if (this->isMac()) {
575            info->fFlags = FormatInfo::kAllFlags;
576        } else {
577            info->fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kRenderable_Flag;
578        }
579        info->fColorTypeInfoCount = 1;
580        info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
581        int ctIdx = 0;
582        // Format: RG16Unorm, Surface: kR16G16_unorm
583        {
584            auto& ctInfo = info->fColorTypeInfos[ctIdx++];
585            ctInfo.fColorType = kR16G16_unorm_SkColorType;
586            ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
587        }
588    }
589
590    // Format: ETC2_RGB8
591    {
592        if (@available(macOS 11.0, iOS 8.0, tvOS 9.0, *)) {
593            if (this->isApple()) {
594                info = &fFormatTable[GetFormatIndex(MTLPixelFormatETC2_RGB8)];
595                info->fFlags = FormatInfo::kTexturable_Flag;
596                info->fColorTypeInfoCount = 1;
597                info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
598                int ctIdx = 0;
599                // Format: ETC2_RGB8, Surface: kRGB_888x
600                {
601                    auto& ctInfo = info->fColorTypeInfos[ctIdx++];
602                    ctInfo.fColorType = kRGB_888x_SkColorType;
603                    ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
604                }
605            }
606        }
607    }
608
609    // Format: BC1_RGBA
610    {
611#ifdef SK_BUILD_FOR_MAC
612        if (this->isMac()) {
613            info = &fFormatTable[GetFormatIndex(MTLPixelFormatBC1_RGBA)];
614            info->fFlags = FormatInfo::kTexturable_Flag;
615            info->fColorTypeInfoCount = 1;
616            info->fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info->fColorTypeInfoCount);
617            int ctIdx = 0;
618            // Format: BC1_RGBA, Surface: kRGBA_8888
619            {
620                auto& ctInfo = info->fColorTypeInfos[ctIdx++];
621                ctInfo.fColorType = kRGBA_8888_SkColorType;
622                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
623            }
624        }
625#endif
626    }
627
628    /*
629     * Non-color formats
630     */
631
632    // Format: Stencil8
633    {
634        info = &fFormatTable[GetFormatIndex(MTLPixelFormatStencil8)];
635        info->fFlags = FormatInfo::kMSAA_Flag;
636        info->fColorTypeInfoCount = 0;
637    }
638
639    // Format: Depth16Unorm
640    {
641        info = &fFormatTable[GetFormatIndex(MTLPixelFormatDepth16Unorm)];
642        info->fFlags = FormatInfo::kMSAA_Flag;
643        if (this->isMac() || fFamilyGroup >= 3) {
644            info->fFlags |= FormatInfo::kResolve_Flag;
645        }
646        info->fColorTypeInfoCount = 0;
647    }
648
649    // Format: Depth32Float
650    {
651        info = &fFormatTable[GetFormatIndex(MTLPixelFormatDepth32Float)];
652        info->fFlags = FormatInfo::kMSAA_Flag;
653        if (this->isMac() || fFamilyGroup >= 3) {
654            info->fFlags |= FormatInfo::kResolve_Flag;
655        }
656        info->fColorTypeInfoCount = 0;
657    }
658
659    // Format: Depth24Unorm_Stencil8
660    {
661#ifdef SK_BUILD_FOR_MAC
662        if (this->isMac() && [device isDepth24Stencil8PixelFormatSupported]) {
663            info = &fFormatTable[GetFormatIndex(MTLPixelFormatDepth24Unorm_Stencil8)];
664            info->fFlags = FormatInfo::kMSAA_Flag | FormatInfo::kResolve_Flag;
665            info->fColorTypeInfoCount = 0;
666        }
667#endif
668    }
669
670    // Format: Depth32Float_Stencil8
671    {
672        info = &fFormatTable[GetFormatIndex(MTLPixelFormatDepth32Float_Stencil8)];
673        info->fFlags = FormatInfo::kMSAA_Flag;
674        if (this->isMac() || fFamilyGroup >= 3) {
675            info->fFlags |= FormatInfo::kResolve_Flag;
676        }
677        info->fColorTypeInfoCount = 0;
678    }
679
680    ////////////////////////////////////////////////////////////////////////////
681    // Map SkColorTypes (used for creating SkSurfaces) to MTLPixelFormats. The order in which the
682    // formats are passed into the setColorType function indicates the priority in selecting which
683    // format we use for a given SkColorType.
684
685    std::fill_n(fColorTypeToFormatTable, kSkColorTypeCnt, MTLPixelFormatInvalid);
686
687    this->setColorType(kAlpha_8_SkColorType,          { MTLPixelFormatR8Unorm,
688                                                        MTLPixelFormatA8Unorm });
689    if (@available(macOS 11.0, iOS 8.0, tvOS 9.0, *)) {
690        if (this->isApple()) {
691            this->setColorType(kRGB_565_SkColorType,   {MTLPixelFormatB5G6R5Unorm});
692            this->setColorType(kARGB_4444_SkColorType, { MTLPixelFormatABGR4Unorm });
693        }
694    }
695
696    this->setColorType(kRGBA_8888_SkColorType,        { MTLPixelFormatRGBA8Unorm });
697    this->setColorType(kRGB_888x_SkColorType,         { MTLPixelFormatRGBA8Unorm });
698    this->setColorType(kBGRA_8888_SkColorType,        { MTLPixelFormatBGRA8Unorm });
699    this->setColorType(kRGBA_1010102_SkColorType,     { MTLPixelFormatRGB10A2Unorm });
700    this->setColorType(kRGB_101010x_SkColorType,      { MTLPixelFormatRGB10A2Unorm });
701    // kBGRA_1010102_SkColorType
702    // kBGR_101010x_SkColorType
703    // kBGR_101010x_XR_SkColorType
704    this->setColorType(kGray_8_SkColorType,           { MTLPixelFormatR8Unorm });
705    this->setColorType(kRGBA_F16Norm_SkColorType,     { MTLPixelFormatRGBA16Float });
706    this->setColorType(kRGBA_F16_SkColorType,         { MTLPixelFormatRGBA16Float });
707    this->setColorType(kRGB_F16F16F16x_SkColorType,   { MTLPixelFormatRGBA16Float });
708    // kRGBA_F32_SkColorType
709    this->setColorType(kR8G8_unorm_SkColorType,       { MTLPixelFormatRG8Unorm });
710    this->setColorType(kA16_float_SkColorType,        { MTLPixelFormatR16Float });
711    this->setColorType(kR16G16_float_SkColorType,     { MTLPixelFormatRG16Float });
712    this->setColorType(kA16_unorm_SkColorType,        { MTLPixelFormatR16Unorm });
713    this->setColorType(kR16G16_unorm_SkColorType,     { MTLPixelFormatRG16Unorm });
714    this->setColorType(kR16G16B16A16_unorm_SkColorType,{ MTLPixelFormatRGBA16Unorm });
715    this->setColorType(kSRGBA_8888_SkColorType,       { MTLPixelFormatRGBA8Unorm_sRGB });
716    this->setColorType(kR8_unorm_SkColorType,         { MTLPixelFormatR8Unorm });
717
718}
719
720TextureInfo MtlCaps::getDefaultSampledTextureInfo(SkColorType colorType,
721                                                  Mipmapped mipmapped,
722                                                  Protected,
723                                                  Renderable renderable) const {
724    MTLTextureUsage usage = MTLTextureUsageShaderRead;
725    if (renderable == Renderable::kYes) {
726        usage |= MTLTextureUsageRenderTarget;
727    }
728
729    MTLPixelFormat format = this->getFormatFromColorType(colorType);
730    if (format == MTLPixelFormatInvalid) {
731        return {};
732    }
733
734    MtlTextureInfo info;
735    info.fSampleCount = 1;
736    info.fMipmapped = mipmapped;
737    info.fFormat = format;
738    info.fUsage = usage;
739    info.fStorageMode = MTLStorageModePrivate;
740    info.fFramebufferOnly = false;
741
742    return TextureInfos::MakeMetal(info);
743}
744
745TextureInfo MtlCaps::getTextureInfoForSampledCopy(const TextureInfo& textureInfo,
746                                                  Mipmapped mipmapped) const {
747    MtlTextureInfo info;
748    if (!TextureInfos::GetMtlTextureInfo(textureInfo, &info)) {
749        return {};
750    }
751
752    info.fSampleCount = 1;
753    info.fMipmapped = mipmapped;
754    info.fUsage = MTLTextureUsageShaderRead;
755    info.fStorageMode = MTLStorageModePrivate;
756    info.fFramebufferOnly = false;
757
758    return TextureInfos::MakeMetal(info);
759}
760
761namespace {
762
763skgpu::UniqueKey::Domain get_domain() {
764    static const skgpu::UniqueKey::Domain kMtlGraphicsPipelineDomain =
765            skgpu::UniqueKey::GenerateDomain();
766
767    return kMtlGraphicsPipelineDomain;
768}
769
770MTLPixelFormat format_from_compression(SkTextureCompressionType compression) {
771    switch (compression) {
772        case SkTextureCompressionType::kETC2_RGB8_UNORM:
773            return kMTLPixelFormatETC2_RGB8;
774        case SkTextureCompressionType::kBC1_RGBA8_UNORM:
775#ifdef SK_BUILD_FOR_MAC
776            return MTLPixelFormatBC1_RGBA;
777#endif
778        default:
779            return MTLPixelFormatInvalid;
780    }
781}
782}
783
784TextureInfo MtlCaps::getDefaultCompressedTextureInfo(SkTextureCompressionType compression,
785                                                     Mipmapped mipmapped,
786                                                     Protected) const {
787    MTLTextureUsage usage = MTLTextureUsageShaderRead;
788
789    MTLPixelFormat format = format_from_compression(compression);
790    if (format == MTLPixelFormatInvalid) {
791        return {};
792    }
793
794    MtlTextureInfo info;
795    info.fSampleCount = 1;
796    info.fMipmapped = mipmapped;
797    info.fFormat = format;
798    info.fUsage = usage;
799    info.fStorageMode = MTLStorageModePrivate;
800    info.fFramebufferOnly = false;
801
802    return TextureInfos::MakeMetal(info);
803}
804
805MTLStorageMode MtlCaps::getDefaultMSAAStorageMode(Discardable discardable) const {
806    // Try to use memoryless if it's available (only on new Apple silicon)
807    if (discardable == Discardable::kYes && this->isApple()) {
808        if (@available(macOS 11.0, iOS 10.0, tvOS 10.0, *)) {
809            return MTLStorageModeMemoryless;
810        }
811    }
812    // If it's not discardable or not available, private is the best option
813    return MTLStorageModePrivate;
814}
815
816TextureInfo MtlCaps::getDefaultMSAATextureInfo(const TextureInfo& singleSampledInfo,
817                                               Discardable discardable) const {
818    if (fDefaultMSAASamples <= 1) {
819        return {};
820    }
821    MTLPixelFormat format = TextureInfos::GetMTLPixelFormat(singleSampledInfo);
822    if (!this->isRenderable(format, fDefaultMSAASamples)) {
823        return {};
824    }
825
826    MTLTextureUsage usage = MTLTextureUsageRenderTarget;
827
828    MtlTextureInfo info;
829    info.fSampleCount = fDefaultMSAASamples;
830    info.fMipmapped = Mipmapped::kNo;
831    info.fFormat = format;
832    info.fUsage = usage;
833    info.fStorageMode = this->getDefaultMSAAStorageMode(discardable);
834    info.fFramebufferOnly = false;
835
836    return TextureInfos::MakeMetal(info);
837}
838
839MTLPixelFormat MtlCaps::getFormatFromDepthStencilFlags(
840        SkEnumBitMask<DepthStencilFlags> mask) const {
841    // TODO: Decide if we want to change this to always return a combined depth and stencil format
842    // to allow more sharing of depth stencil allocations.
843    if (mask == DepthStencilFlags::kDepth) {
844        // Graphite only needs 16-bits for depth values, so save some memory. If needed for
845        // workarounds, MTLPixelFormatDepth32Float is also available.
846        return MTLPixelFormatDepth16Unorm;
847    } else if (mask == DepthStencilFlags::kStencil) {
848        return MTLPixelFormatStencil8;
849    } else if (mask == DepthStencilFlags::kDepthStencil) {
850#if defined(SK_BUILD_FOR_MAC)
851        if (SkToBool(this->getFormatInfo(MTLPixelFormatDepth24Unorm_Stencil8).fFlags)) {
852            return MTLPixelFormatDepth24Unorm_Stencil8;
853        }
854#endif
855        return MTLPixelFormatDepth32Float_Stencil8;
856    }
857    SkASSERT(false);
858    return MTLPixelFormatInvalid;
859}
860
861TextureInfo MtlCaps::getDefaultDepthStencilTextureInfo(
862            SkEnumBitMask<DepthStencilFlags> depthStencilType,
863            uint32_t sampleCount,
864            Protected) const {
865    MtlTextureInfo info;
866    info.fSampleCount = sampleCount;
867    info.fMipmapped = Mipmapped::kNo;
868    info.fFormat = this->getFormatFromDepthStencilFlags(depthStencilType);
869    info.fUsage = MTLTextureUsageRenderTarget;
870    info.fStorageMode = this->getDefaultMSAAStorageMode(Discardable::kYes);
871    info.fFramebufferOnly = false;
872
873    return TextureInfos::MakeMetal(info);
874}
875
876TextureInfo MtlCaps::getDefaultStorageTextureInfo(SkColorType colorType) const {
877    // Storage textures are currently always sampleable from a shader.
878    MTLPixelFormat format = static_cast<MTLPixelFormat>(this->getFormatFromColorType(colorType));
879    if (format == MTLPixelFormatInvalid) {
880        return {};
881    }
882
883    const FormatInfo& formatInfo = this->getFormatInfo(format);
884    if (!SkToBool(FormatInfo::kStorage_Flag & formatInfo.fFlags)) {
885        return {};
886    }
887
888    MTLTextureUsage usage = MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead;
889    MtlTextureInfo info;
890    info.fSampleCount = 1;
891    info.fMipmapped = Mipmapped::kNo;
892    info.fFormat = format;
893    info.fUsage = usage;
894    info.fStorageMode = MTLStorageModePrivate;
895    info.fFramebufferOnly = false;
896
897    return TextureInfos::MakeMetal(info);
898}
899
900const Caps::ColorTypeInfo* MtlCaps::getColorTypeInfo(
901        SkColorType ct, const TextureInfo& textureInfo) const {
902    MTLPixelFormat mtlFormat = TextureInfos::GetMTLPixelFormat(textureInfo);
903    if (mtlFormat == MTLPixelFormatInvalid) {
904        return nullptr;
905    }
906
907    const FormatInfo& info = this->getFormatInfo(mtlFormat);
908    for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
909        const ColorTypeInfo& ctInfo = info.fColorTypeInfos[i];
910        if (ctInfo.fColorType == ct) {
911            return &ctInfo;
912        }
913    }
914
915    return nullptr;
916}
917
918static const int kMtlGraphicsPipelineKeyData32Count = 5;
919
920UniqueKey MtlCaps::makeGraphicsPipelineKey(const GraphicsPipelineDesc& pipelineDesc,
921                                           const RenderPassDesc& renderPassDesc) const {
922    UniqueKey pipelineKey;
923    {
924        // 5 uint32_t's (render step id, paint id, uint64 renderpass desc, uint16 write swizzle key)
925        UniqueKey::Builder builder(&pipelineKey, get_domain(),
926                                   kMtlGraphicsPipelineKeyData32Count, "MtlGraphicsPipeline");
927        // add GraphicsPipelineDesc key
928        builder[0] = pipelineDesc.renderStepID();
929        builder[1] = pipelineDesc.paintParamsID().asUInt();
930
931        // add RenderPassDesc key
932        uint64_t renderPassKey = this->getRenderPassDescKey(renderPassDesc);
933        builder[2] = renderPassKey & 0xFFFFFFFF;
934        builder[3] = (renderPassKey >> 32) & 0xFFFFFFFF;
935        builder[4] = renderPassDesc.fWriteSwizzle.asKey();
936
937        builder.finish();
938    }
939
940    return pipelineKey;
941}
942
943bool MtlCaps::extractGraphicsDescs(const UniqueKey& key,
944                                   GraphicsPipelineDesc* pipelineDesc,
945                                   RenderPassDesc* renderPassDesc,
946                                   const RendererProvider* rendererProvider) const {
947    struct UnpackedKeyData {
948        // From the GraphicsPipelineDesc
949        uint32_t fRenderStepID = 0;
950        UniquePaintParamsID fPaintParamsID;
951
952        // From the RenderPassDesc
953        MTLPixelFormat fColorFormat = MTLPixelFormatInvalid;
954        uint32_t fColorSampleCount = 1;
955
956        MTLPixelFormat fDSFormat = MTLPixelFormatInvalid;
957        uint32_t fDSSampleCount = 1;
958
959        Swizzle fWriteSwizzle;
960    } keyData;
961
962    SkASSERT(key.domain() == get_domain());
963    SkASSERT(key.dataSize() == 4 * kMtlGraphicsPipelineKeyData32Count);
964
965    const uint32_t* rawKeyData = key.data();
966
967    keyData.fRenderStepID = rawKeyData[0];
968    keyData.fPaintParamsID = rawKeyData[1] ? UniquePaintParamsID(rawKeyData[1])
969                                           : UniquePaintParamsID::InvalidID();
970
971    keyData.fDSFormat = static_cast<MTLPixelFormat>((rawKeyData[2] >> 16) & 0xFFFF);
972    keyData.fDSSampleCount = rawKeyData[2] & 0xFFFF;
973
974    keyData.fColorFormat = static_cast<MTLPixelFormat>((rawKeyData[3] >> 16) & 0xFFFF);
975    keyData.fColorSampleCount = rawKeyData[3] & 0xFFFF;
976
977    keyData.fWriteSwizzle = SwizzleCtorAccessor::Make(rawKeyData[4]);
978
979    // Recreate the RenderPassDesc
980    SkASSERT(keyData.fColorSampleCount == keyData.fDSSampleCount);
981
982    MTLPixelFormat dsFormat = keyData.fDSFormat;
983    SkEnumBitMask<DepthStencilFlags> dsFlags = DepthStencilFlags::kNone;
984    if (MtlFormatIsDepth(dsFormat)) {
985        dsFlags |= DepthStencilFlags::kDepth;
986    }
987    if (MtlFormatIsStencil(dsFormat)) {
988        dsFlags |= DepthStencilFlags::kStencil;
989    }
990
991    MtlTextureInfo mtlInfo(keyData.fColorSampleCount,
992                           skgpu::Mipmapped::kNo,
993                           keyData.fColorFormat,
994                           MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget,
995                           MTLStorageModePrivate,
996                           /* framebufferOnly= */ false);
997    TextureInfo info = TextureInfos::MakeMetal(mtlInfo);
998
999    *renderPassDesc = RenderPassDesc::Make(this,
1000                                           info,
1001                                           LoadOp::kClear,
1002                                           StoreOp::kStore,
1003                                           dsFlags,
1004                                           /* clearColor= */ { .0f, .0f, .0f, .0f },
1005                                           /* requiresMSAA= */ keyData.fColorSampleCount > 1,
1006                                           keyData.fWriteSwizzle);
1007
1008    // Recreate the GraphicsPipelineDesc
1009    const RenderStep* renderStep = rendererProvider->lookup(keyData.fRenderStepID);
1010
1011    UniquePaintParamsID paintID = renderStep->performsShading() ? keyData.fPaintParamsID
1012                                                                : UniquePaintParamsID::InvalidID();
1013
1014    *pipelineDesc = GraphicsPipelineDesc(renderStep, paintID);
1015
1016    return true;
1017}
1018
1019uint64_t MtlCaps::getRenderPassDescKey(const RenderPassDesc& renderPassDesc) const {
1020    MtlTextureInfo colorInfo, depthStencilInfo;
1021    SkAssertResult(TextureInfos::GetMtlTextureInfo(renderPassDesc.fColorAttachment.fTextureInfo,
1022                                                   &colorInfo));
1023    SkAssertResult(TextureInfos::GetMtlTextureInfo(
1024            renderPassDesc.fDepthStencilAttachment.fTextureInfo, &depthStencilInfo));
1025    SkASSERT(colorInfo.fFormat < 65535 && depthStencilInfo.fFormat < 65535);
1026    uint32_t colorAttachmentKey = colorInfo.fFormat << 16 | colorInfo.fSampleCount;
1027    uint32_t dsAttachmentKey = depthStencilInfo.fFormat << 16 | depthStencilInfo.fSampleCount;
1028    return (((uint64_t) colorAttachmentKey) << 32) | dsAttachmentKey;
1029}
1030
1031UniqueKey MtlCaps::makeComputePipelineKey(const ComputePipelineDesc& pipelineDesc) const {
1032    UniqueKey pipelineKey;
1033    {
1034        static const skgpu::UniqueKey::Domain kComputePipelineDomain = UniqueKey::GenerateDomain();
1035        // The key is made up of a single uint32_t corresponding to the compute step ID.
1036        UniqueKey::Builder builder(&pipelineKey, kComputePipelineDomain, 1, "ComputePipeline");
1037        builder[0] = pipelineDesc.computeStep()->uniqueID();
1038
1039        // TODO(b/240615224): The local work group size should factor into the key on platforms
1040        // that don't support specialization constants and require the workgroup/threadgroup size to
1041        // be specified in the shader text (D3D12, Vulkan 1.0, and OpenGL).
1042
1043        builder.finish();
1044    }
1045    return pipelineKey;
1046}
1047
1048uint32_t MtlCaps::channelMask(const TextureInfo& info) const {
1049    return skgpu::MtlFormatChannels(TextureInfos::GetMTLPixelFormat(info));
1050}
1051
1052bool MtlCaps::onIsTexturable(const TextureInfo& info) const {
1053    if (!info.isValid()) {
1054        return false;
1055    }
1056    if (!(TextureInfos::GetMTLTextureUsage(info) & MTLTextureUsageShaderRead)) {
1057        return false;
1058    }
1059    if (TextureInfos::GetMtlFramebufferOnly(info)) {
1060        return false;
1061    }
1062    return this->isTexturable(TextureInfos::GetMTLPixelFormat(info));
1063}
1064
1065bool MtlCaps::isTexturable(MTLPixelFormat format) const {
1066    const FormatInfo& formatInfo = this->getFormatInfo(format);
1067    return SkToBool(FormatInfo::kTexturable_Flag & formatInfo.fFlags);
1068}
1069
1070bool MtlCaps::isRenderable(const TextureInfo& info) const {
1071    return info.isValid() &&
1072           (TextureInfos::GetMTLTextureUsage(info) & MTLTextureUsageRenderTarget) &&
1073           this->isRenderable(TextureInfos::GetMTLPixelFormat(info), info.numSamples());
1074}
1075
1076bool MtlCaps::isRenderable(MTLPixelFormat format, uint32_t sampleCount) const {
1077    return sampleCount <= this->maxRenderTargetSampleCount(format);
1078}
1079
1080bool MtlCaps::isStorage(const TextureInfo& info) const {
1081    if (!info.isValid()) {
1082        return false;
1083    }
1084    if (!(TextureInfos::GetMTLTextureUsage(info) & MTLTextureUsageShaderWrite)) {
1085        return false;
1086    }
1087    if (TextureInfos::GetMtlFramebufferOnly(info)) {
1088        return false;
1089    }
1090    const FormatInfo& formatInfo = this->getFormatInfo(TextureInfos::GetMTLPixelFormat(info));
1091    return info.numSamples() == 1 && SkToBool(FormatInfo::kStorage_Flag & formatInfo.fFlags);
1092}
1093
1094uint32_t MtlCaps::maxRenderTargetSampleCount(MTLPixelFormat format) const {
1095    const FormatInfo& formatInfo = this->getFormatInfo(format);
1096    if (!SkToBool(formatInfo.fFlags & FormatInfo::kRenderable_Flag)) {
1097        return 0;
1098    }
1099    if (SkToBool(formatInfo.fFlags & FormatInfo::kMSAA_Flag)) {
1100        return fColorSampleCounts[fColorSampleCounts.size() - 1];
1101    } else {
1102        return 1;
1103    }
1104}
1105
1106bool MtlCaps::supportsWritePixels(const TextureInfo& texInfo) const {
1107    MtlTextureInfo mtlInfo;
1108    if (!TextureInfos::GetMtlTextureInfo(texInfo, &mtlInfo)) {
1109        return false;
1110    }
1111    if (mtlInfo.fFramebufferOnly) {
1112        return false;
1113    }
1114
1115    if (texInfo.numSamples() > 1) {
1116        return false;
1117    }
1118
1119    return true;
1120}
1121
1122bool MtlCaps::supportsReadPixels(const TextureInfo& texInfo) const {
1123    MtlTextureInfo mtlInfo;
1124    if (!TextureInfos::GetMtlTextureInfo(texInfo, &mtlInfo)) {
1125        return false;
1126    }
1127    if (mtlInfo.fFramebufferOnly) {
1128        return false;
1129    }
1130
1131    // We disallow reading back directly from compressed textures.
1132    if (MtlFormatIsCompressed(mtlInfo.fFormat)) {
1133        return false;
1134    }
1135
1136    if (texInfo.numSamples() > 1) {
1137        return false;
1138    }
1139
1140    return true;
1141}
1142
1143std::pair<SkColorType, bool /*isRGBFormat*/> MtlCaps::supportedWritePixelsColorType(
1144        SkColorType dstColorType,
1145        const TextureInfo& dstTextureInfo,
1146        SkColorType srcColorType) const {
1147    MtlTextureInfo mtlInfo;
1148    if (!TextureInfos::GetMtlTextureInfo(dstTextureInfo, &mtlInfo)) {
1149        return {kUnknown_SkColorType, false};
1150    }
1151
1152    const FormatInfo& info = this->getFormatInfo(mtlInfo.fFormat);
1153    for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1154        const auto& ctInfo = info.fColorTypeInfos[i];
1155        if (ctInfo.fColorType == dstColorType) {
1156            return {dstColorType, false};
1157        }
1158    }
1159    return {kUnknown_SkColorType, false};
1160}
1161
1162std::pair<SkColorType, bool /*isRGBFormat*/> MtlCaps::supportedReadPixelsColorType(
1163        SkColorType srcColorType,
1164        const TextureInfo& srcTextureInfo,
1165        SkColorType dstColorType) const {
1166    MtlTextureInfo mtlInfo;
1167    if (!TextureInfos::GetMtlTextureInfo(srcTextureInfo, &mtlInfo)) {
1168        return {kUnknown_SkColorType, false};
1169    }
1170
1171    // TODO: handle compressed formats
1172    if (MtlFormatIsCompressed(mtlInfo.fFormat)) {
1173        SkASSERT(this->isTexturable(mtlInfo.fFormat));
1174        return {kUnknown_SkColorType, false};
1175    }
1176
1177    const FormatInfo& info = this->getFormatInfo(mtlInfo.fFormat);
1178    for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1179        const auto& ctInfo = info.fColorTypeInfos[i];
1180        if (ctInfo.fColorType == srcColorType) {
1181            return {srcColorType, false};
1182        }
1183    }
1184    return {kUnknown_SkColorType, false};
1185}
1186
1187void MtlCaps::buildKeyForTexture(SkISize dimensions,
1188                                 const TextureInfo& info,
1189                                 ResourceType type,
1190                                 Shareable shareable,
1191                                 GraphiteResourceKey* key) const {
1192    const MtlTextureSpec mtlSpec = TextureInfos::GetMtlTextureSpec(info);
1193
1194    SkASSERT(!dimensions.isEmpty());
1195
1196    // A MTLPixelFormat is an NSUInteger type which is documented to be 32 bits in 32 bit
1197    // applications and 64 bits in 64 bit applications. So it should fit in an uint64_t, but adding
1198    // the assert heere to make sure.
1199    static_assert(sizeof(MTLPixelFormat) <= sizeof(uint64_t));
1200    SkASSERT(mtlSpec.fFormat != MTLPixelFormatInvalid);
1201    uint64_t formatKey = static_cast<uint64_t>(mtlSpec.fFormat);
1202
1203    uint32_t samplesKey = SamplesToKey(info.numSamples());
1204    // We don't have to key the number of mip levels because it is inherit in the combination of
1205    // isMipped and dimensions.
1206    bool isMipped = info.mipmapped() == Mipmapped::kYes;
1207    Protected isProtected = info.isProtected();
1208    bool isFBOnly = mtlSpec.fFramebufferOnly;
1209
1210    // Confirm all the below parts of the key can fit in a single uint32_t. The sum of the shift
1211    // amounts in the asserts must be less than or equal to 32.
1212    SkASSERT(samplesKey                         < (1u << 3));
1213    SkASSERT(static_cast<uint32_t>(isMipped)    < (1u << 1));
1214    SkASSERT(static_cast<uint32_t>(isProtected) < (1u << 1));
1215    SkASSERT(mtlSpec.fUsage                     < (1u << 5));
1216    SkASSERT(mtlSpec.fStorageMode               < (1u << 2));
1217    SkASSERT(static_cast<uint32_t>(isFBOnly)    < (1u << 1));
1218
1219    // We need two uint32_ts for dimensions, 2 for format, and 1 for the rest of the key;
1220    static int kNum32DataCnt = 2 + 2 + 1;
1221
1222    GraphiteResourceKey::Builder builder(key, type, kNum32DataCnt, shareable);
1223
1224    builder[0] = dimensions.width();
1225    builder[1] = dimensions.height();
1226    builder[2] = formatKey & 0xFFFFFFFF;
1227    builder[3] = (formatKey >> 32) & 0xFFFFFFFF;
1228    builder[4] = (samplesKey                                  << 0) |
1229                 (static_cast<uint32_t>(isMipped)             << 3) |
1230                 (static_cast<uint32_t>(isProtected)          << 4) |
1231                 (static_cast<uint32_t>(mtlSpec.fUsage)       << 5) |
1232                 (static_cast<uint32_t>(mtlSpec.fStorageMode) << 10)|
1233                 (static_cast<uint32_t>(isFBOnly)             << 12);
1234
1235}
1236
1237} // namespace skgpu::graphite
1238