1/*
2 * Copyright 2017 Google Inc.
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 "GrMtlGpu.h"
9
10#include "GrMtlTexture.h"
11
12#if !__has_feature(objc_arc)
13#error This file must be compiled with Arc. Use -fobjc-arc flag
14#endif
15
16static bool get_feature_set(id<MTLDevice> device, MTLFeatureSet* featureSet) {
17    // Mac OSX
18#ifdef SK_BUILD_FOR_MAC
19    if ([device supportsFeatureSet:MTLFeatureSet_OSX_GPUFamily1_v2]) {
20        *featureSet = MTLFeatureSet_OSX_GPUFamily1_v2;
21        return true;
22    }
23    if ([device supportsFeatureSet:MTLFeatureSet_OSX_GPUFamily1_v1]) {
24        *featureSet = MTLFeatureSet_OSX_GPUFamily1_v1;
25        return true;
26    }
27#endif
28
29    // iOS Family group 3
30#ifdef SK_BUILD_FOR_IOS
31    if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2]) {
32        *featureSet = MTLFeatureSet_iOS_GPUFamily3_v2;
33        return true;
34    }
35    if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
36        *featureSet = MTLFeatureSet_iOS_GPUFamily3_v1;
37        return true;
38    }
39
40    // iOS Family group 2
41    if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v3]) {
42        *featureSet = MTLFeatureSet_iOS_GPUFamily2_v3;
43        return true;
44    }
45    if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2]) {
46        *featureSet = MTLFeatureSet_iOS_GPUFamily2_v2;
47        return true;
48    }
49    if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1]) {
50        *featureSet = MTLFeatureSet_iOS_GPUFamily2_v1;
51        return true;
52    }
53
54    // iOS Family group 1
55    if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v3]) {
56        *featureSet = MTLFeatureSet_iOS_GPUFamily1_v3;
57        return true;
58    }
59    if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
60        *featureSet = MTLFeatureSet_iOS_GPUFamily1_v2;
61        return true;
62    }
63    if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v1]) {
64        *featureSet = MTLFeatureSet_iOS_GPUFamily1_v1;
65        return true;
66    }
67#endif
68    // No supported feature sets were found
69    return false;
70}
71
72sk_sp<GrGpu> GrMtlGpu::Make(GrContext* context, const GrContextOptions& options,
73                            id<MTLDevice> device, id<MTLCommandQueue> queue) {
74    if (!device || !queue) {
75        return nullptr;
76    }
77    MTLFeatureSet featureSet;
78    if (!get_feature_set(device, &featureSet)) {
79        return nullptr;
80    }
81    return sk_sp<GrGpu>(new GrMtlGpu(context, options, device, queue, featureSet));
82}
83
84GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options,
85                   id<MTLDevice> device, id<MTLCommandQueue> queue, MTLFeatureSet featureSet)
86        : INHERITED(context)
87        , fDevice(device)
88        , fQueue(queue) {
89
90    fMtlCaps.reset(new GrMtlCaps(options, fDevice, featureSet));
91    fCaps = fMtlCaps;
92
93    MTLTextureDescriptor* txDesc = [[MTLTextureDescriptor alloc] init];
94    txDesc.textureType = MTLTextureType3D;
95    txDesc.height = 64;
96    txDesc.width = 64;
97    txDesc.depth = 64;
98    txDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
99    txDesc.arrayLength = 1;
100    txDesc.mipmapLevelCount = 1;
101    id<MTLTexture> testTexture = [fDevice newTextureWithDescriptor:txDesc];
102    // To get ride of unused var warning
103    int width = [testTexture width];
104    SkDebugf("width: %d\n", width);
105    // Unused queue warning fix
106    SkDebugf("ptr to queue: %p\n", fQueue);
107}
108
109sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
110                                           const GrMipLevel texels[], int mipLevelCount) {
111    int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
112
113    if (!fMtlCaps->isConfigTexturable(desc.fConfig)) {
114        return nullptr;
115    }
116
117    bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
118    if (renderTarget) {
119        // Current we don't have render target support
120        return nullptr;
121    }
122
123    sk_sp<GrMtlTexture> tex;
124    if (renderTarget) {
125        // Enable once we have render target support
126#if 0
127        tex = GrMtlTextureRenderTarget::CreateNewTextureRenderTarget(this, budgeted,
128                                                                    desc, mipLevels);
129#endif
130    } else {
131        tex = GrMtlTexture::CreateNewTexture(this, budgeted, desc, mipLevels);
132    }
133
134    if (!tex) {
135        return nullptr;
136    }
137
138    if (mipLevelCount) {
139        // Perform initial data upload here
140    }
141
142    if (desc.fFlags & kPerformInitialClear_GrSurfaceFlag) {
143        // Do initial clear of the texture
144    }
145    return tex;
146}
147