blob: 2527be9ceb9f47ca24064b66d57a53d943f8602b [file] [log] [blame]
Greg Danielcebcb842017-07-31 10:45:52 -04001/*
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 "GrMtlCaps.h"
9
Timothy Liang036fdfe2018-06-28 15:50:36 -040010#include "GrBackendSurface.h"
Timothy Liang4e85e802018-06-28 16:37:18 -040011#include "GrMtlUtil.h"
Greg Danielcebcb842017-07-31 10:45:52 -040012#include "GrShaderCaps.h"
13
14GrMtlCaps::GrMtlCaps(const GrContextOptions& contextOptions, const id<MTLDevice> device,
15 MTLFeatureSet featureSet)
16 : INHERITED(contextOptions) {
17 fShaderCaps.reset(new GrShaderCaps(contextOptions));
18
19 this->initFeatureSet(featureSet);
20 this->initGrCaps(device);
21 this->initShaderCaps();
22 this->initConfigTable();
23
24 this->applyOptionsOverrides(contextOptions);
25 fShaderCaps->applyOptionsOverrides(contextOptions);
26}
27
28void GrMtlCaps::initFeatureSet(MTLFeatureSet featureSet) {
29 // Mac OSX
30#ifdef SK_BUILD_FOR_MAC
31 if (MTLFeatureSet_OSX_GPUFamily1_v2 == featureSet) {
32 fPlatform = Platform::kMac;
33 fFamilyGroup = 1;
34 fVersion = 2;
35 return;
36 }
37 if (MTLFeatureSet_OSX_GPUFamily1_v1 == featureSet) {
38 fPlatform = Platform::kMac;
39 fFamilyGroup = 1;
40 fVersion = 1;
41 return;
42 }
43#endif
44
45 // iOS Family group 3
46#ifdef SK_BUILD_FOR_IOS
47 if (MTLFeatureSet_iOS_GPUFamily3_v2 == featureSet) {
48 fPlatform = Platform::kIOS;
49 fFamilyGroup = 3;
50 fVersion = 2;
51 return;
52 }
53 if (MTLFeatureSet_iOS_GPUFamily3_v1 == featureSet) {
54 fPlatform = Platform::kIOS;
55 fFamilyGroup = 3;
56 fVersion = 1;
57 return;
58 }
59
60 // iOS Family group 2
61 if (MTLFeatureSet_iOS_GPUFamily2_v3 == featureSet) {
62 fPlatform = Platform::kIOS;
63 fFamilyGroup = 2;
64 fVersion = 3;
65 return;
66 }
67 if (MTLFeatureSet_iOS_GPUFamily2_v2 == featureSet) {
68 fPlatform = Platform::kIOS;
69 fFamilyGroup = 2;
70 fVersion = 2;
71 return;
72 }
73 if (MTLFeatureSet_iOS_GPUFamily2_v1 == featureSet) {
74 fPlatform = Platform::kIOS;
75 fFamilyGroup = 2;
76 fVersion = 1;
77 return;
78 }
79
80 // iOS Family group 1
81 if (MTLFeatureSet_iOS_GPUFamily1_v3 == featureSet) {
82 fPlatform = Platform::kIOS;
83 fFamilyGroup = 1;
84 fVersion = 3;
85 return;
86 }
87 if (MTLFeatureSet_iOS_GPUFamily1_v2 == featureSet) {
88 fPlatform = Platform::kIOS;
89 fFamilyGroup = 1;
90 fVersion = 2;
91 return;
92 }
93 if (MTLFeatureSet_iOS_GPUFamily1_v1 == featureSet) {
94 fPlatform = Platform::kIOS;
95 fFamilyGroup = 1;
96 fVersion = 1;
97 return;
98 }
99#endif
100 // No supported feature sets were found
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400101 SK_ABORT("Requested an unsupported feature set");
Greg Danielcebcb842017-07-31 10:45:52 -0400102}
103
104void GrMtlCaps::initGrCaps(const id<MTLDevice> device) {
105 // Max vertex attribs is the same on all devices
106 fMaxVertexAttributes = 31;
107
108 // RenderTarget and Texture size
109 if (this->isMac()) {
110 fMaxRenderTargetSize = 16384;
111 } else {
112 if (3 == fFamilyGroup) {
113 fMaxRenderTargetSize = 16384;
114 } else {
115 // Family group 1 and 2 support 8192 for version 2 and above, 4096 for v1
116 if (1 == fVersion) {
117 fMaxRenderTargetSize = 4096;
118 } else {
119 fMaxRenderTargetSize = 8192;
120 }
121 }
122 }
Chris Dalton2612bae2018-02-22 13:41:37 -0700123 fMaxPreferredRenderTargetSize = fMaxRenderTargetSize;
Greg Danielcebcb842017-07-31 10:45:52 -0400124 fMaxTextureSize = fMaxRenderTargetSize;
125
126 // Init sample counts. All devices support 1 (i.e. 0 in skia).
Brian Salomonbdecacf2018-02-02 20:32:49 -0500127 fSampleCounts.push(1);
Greg Danielcebcb842017-07-31 10:45:52 -0400128 for (auto sampleCnt : {2, 4, 8}) {
129 if ([device supportsTextureSampleCount:sampleCnt]) {
130 fSampleCounts.push(sampleCnt);
131 }
132 }
133
134 // Starting with the assumption that there isn't a reason to not map small buffers.
135 fBufferMapThreshold = 0;
136
137 // Buffers are always fully mapped.
138 fMapBufferFlags = kCanMap_MapFlag;
139
140 fOversizedStencilSupport = true;
141
142 // Looks like there is a field called rasterSampleCount labeled as beta in the Metal docs. This
143 // may be what we eventually need here, but it has no description.
144 fSampleShadingSupport = false;
145
146 fSRGBSupport = true; // always available in Metal
147 fSRGBWriteControl = false;
148 fMipMapSupport = true; // always available in Metal
149 fNPOTTextureTileSupport = true; // always available in Metal
150 fDiscardRenderTargetSupport = true;
151
152 fReuseScratchTextures = true; // Assuming this okay
153
154 fTextureBarrierSupport = false; // Need to figure out if we can do this
155
Robert Phillips7f861922018-01-30 13:13:42 +0000156 fSampleLocationsSupport = false;
Greg Danielcebcb842017-07-31 10:45:52 -0400157 fMultisampleDisableSupport = false;
158
159 if (this->isMac() || 3 == fFamilyGroup) {
160 fInstanceAttribSupport = true;
161 }
162
163 fUsesMixedSamples = false;
164 fGpuTracingSupport = false;
165
Greg Danielcebcb842017-07-31 10:45:52 -0400166 fFenceSyncSupport = true; // always available in Metal
167 fCrossContextTextureSupport = false;
Greg Danielcebcb842017-07-31 10:45:52 -0400168}
169
Brian Salomon5bb82cb2018-02-02 13:51:50 -0500170
Brian Salomonbdecacf2018-02-02 20:32:49 -0500171int GrMtlCaps::maxRenderTargetSampleCount(GrPixelConfig config) const {
172 if (fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag) {
173 return fSampleCounts[fSampleCounts.count() - 1];
174 } else if (fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) {
175 return 1;
Brian Salomon5bb82cb2018-02-02 13:51:50 -0500176 }
Brian Salomonbdecacf2018-02-02 20:32:49 -0500177 return 0;
178}
179
180int GrMtlCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const {
181 requestedCount = SkTMax(requestedCount, 1);
182 if (fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag) {
183 int count = fSampleCounts.count();
184 for (int i = 0; i < count; ++i) {
185 if (fSampleCounts[i] >= requestedCount) {
186 return fSampleCounts[i];
187 }
188 }
189 } else if (fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) {
190 return 1 == requestedCount ? 1 : 0;
191 }
192 return 0;
Greg Danielcebcb842017-07-31 10:45:52 -0400193}
194
195void GrMtlCaps::initShaderCaps() {
196 GrShaderCaps* shaderCaps = fShaderCaps.get();
197
198 // fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config.
199 for (int i = 0; i < kGrPixelConfigCnt; ++i) {
200 GrPixelConfig config = static_cast<GrPixelConfig>(i);
201 if (GrPixelConfigIsAlphaOnly(config)) {
202 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR();
203 shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
204 } else {
205 if (kGray_8_GrPixelConfig == config) {
206 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRA();
207 } else {
208 shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA();
209 }
210 }
211 }
212
213 // Setting this true with the assumption that this cap will eventually mean we support varying
Brian Salomon41274562017-09-15 09:40:03 -0700214 // precisions and not just via modifiers.
Greg Danielcebcb842017-07-31 10:45:52 -0400215 shaderCaps->fUsesPrecisionModifiers = true;
216 shaderCaps->fFlatInterpolationSupport = true;
Brian Salomon41274562017-09-15 09:40:03 -0700217 // We haven't yet tested that using flat attributes perform well.
218 shaderCaps->fPreferFlatInterpolation = true;
Greg Danielcebcb842017-07-31 10:45:52 -0400219
220 shaderCaps->fShaderDerivativeSupport = true;
221 shaderCaps->fGeometryShaderSupport = false;
222
223 if ((this->isMac() && fVersion >= 2) ||
224 (this->isIOS() && ((1 == fFamilyGroup && 4 == fVersion) ||
225 (2 == fFamilyGroup && 4 == fVersion) ||
226 (3 == fFamilyGroup && 3 == fVersion)))) {
227 shaderCaps->fDualSourceBlendingSupport = true;
228 }
229
230 if (this->isIOS()) {
231 shaderCaps->fFBFetchSupport = true;
232 shaderCaps->fFBFetchNeedsCustomOutput = true; // ??
233 shaderCaps->fFBFetchColorName = ""; // Somehow add [[color(0)]] to arguments to frag shader
234 }
235 shaderCaps->fDstReadInShaderSupport = shaderCaps->fFBFetchSupport;
236
237 shaderCaps->fIntegerSupport = true;
Greg Danielcebcb842017-07-31 10:45:52 -0400238 shaderCaps->fVertexIDSupport = false;
239 shaderCaps->fImageLoadStoreSupport = false;
Greg Danielcebcb842017-07-31 10:45:52 -0400240
Chris Dalton47c8ed32017-11-15 18:27:09 -0700241 // Metal uses IEEE float and half floats so assuming those values here.
242 shaderCaps->fFloatIs32Bits = true;
243 shaderCaps->fHalfIs32Bits = false;
Greg Danielcebcb842017-07-31 10:45:52 -0400244
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400245 // Metal supports unsigned integers.
246 shaderCaps->fUnsignedSupport = true;
247
Greg Danielcebcb842017-07-31 10:45:52 -0400248 shaderCaps->fMaxVertexSamplers =
249 shaderCaps->fMaxFragmentSamplers = 16;
250 // For now just cap at the per stage max. If we hit this limit we can come back to adjust this
251 shaderCaps->fMaxCombinedSamplers = shaderCaps->fMaxVertexSamplers;
252}
253
254void GrMtlCaps::initConfigTable() {
255 ConfigInfo* info;
256 // Alpha_8 uses R8Unorm
257 info = &fConfigTable[kAlpha_8_GrPixelConfig];
258 info->fFlags = ConfigInfo::kAllFlags;
259
260 // Gray_8 uses R8Unorm
261 info = &fConfigTable[kGray_8_GrPixelConfig];
262 info->fFlags = ConfigInfo::kAllFlags;
263
264 // RGB_565 uses B5G6R5Unorm, even though written opposite this format packs how we want
265 info = &fConfigTable[kRGB_565_GrPixelConfig];
266 if (this->isMac()) {
267 info->fFlags = 0;
268 } else {
269 info->fFlags = ConfigInfo::kAllFlags;
270 }
271
272 // RGBA_4444 uses ABGR4Unorm
273 info = &fConfigTable[kRGBA_4444_GrPixelConfig];
274 if (this->isMac()) {
275 info->fFlags = 0;
276 } else {
277 info->fFlags = ConfigInfo::kAllFlags;
278 }
279
280 // RGBA_8888 uses RGBA8Unorm
281 info = &fConfigTable[kRGBA_8888_GrPixelConfig];
282 info->fFlags = ConfigInfo::kAllFlags;
283
284 // BGRA_8888 uses BGRA8Unorm
285 info = &fConfigTable[kBGRA_8888_GrPixelConfig];
286 info->fFlags = ConfigInfo::kAllFlags;
287
288 // SRGBA_8888 uses RGBA8Unorm_sRGB
289 info = &fConfigTable[kSRGBA_8888_GrPixelConfig];
290 info->fFlags = ConfigInfo::kAllFlags;
291
292 // SBGRA_8888 uses BGRA8Unorm_sRGB
293 info = &fConfigTable[kSBGRA_8888_GrPixelConfig];
294 info->fFlags = ConfigInfo::kAllFlags;
295
Greg Danielcebcb842017-07-31 10:45:52 -0400296 // RGBA_float uses RGBA32Float
297 info = &fConfigTable[kRGBA_float_GrPixelConfig];
298 if (this->isMac()) {
299 info->fFlags = ConfigInfo::kAllFlags;
300 } else {
301 info->fFlags = 0;
302 }
303
304 // RG_float uses RG32Float
305 info = &fConfigTable[kRG_float_GrPixelConfig];
306 if (this->isMac()) {
307 info->fFlags = ConfigInfo::kAllFlags;
308 } else {
309 info->fFlags = ConfigInfo::kRenderable_Flag;
310 }
311
312 // Alpha_half uses R16Float
313 info = &fConfigTable[kAlpha_half_GrPixelConfig];
314 info->fFlags = ConfigInfo::kAllFlags;
315
316 // RGBA_half uses RGBA16Float
317 info = &fConfigTable[kRGBA_half_GrPixelConfig];
318 info->fFlags = ConfigInfo::kAllFlags;
319}
Timothy Liang036fdfe2018-06-28 15:50:36 -0400320
321#ifdef GR_TEST_UTILS
322GrBackendFormat GrMtlCaps::onCreateFormatFromBackendTexture(
323 const GrBackendTexture& backendTex) const {
Timothy Liang4e85e802018-06-28 16:37:18 -0400324 GrMtlTextureInfo mtlInfo;
325 SkAssertResult(backendTex.getMtlTextureInfo(&mtlInfo));
326 id<MTLTexture> mtlTexture = GrGetMTLTexture(mtlInfo.fTexture,
327 GrWrapOwnership::kBorrow_GrWrapOwnership);
328 return GrBackendFormat::MakeMtl(mtlTexture.pixelFormat);
Timothy Liang036fdfe2018-06-28 15:50:36 -0400329}
330#endif
331