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