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