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