• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/gpu/mtl/GrMtlUtil.h"
9
10#include "include/gpu/GrBackendSurface.h"
11#include "include/private/GrTypesPriv.h"
12#include "include/private/SkMutex.h"
13#include "src/core/SkTraceEvent.h"
14#include "src/gpu/GrShaderUtils.h"
15#include "src/gpu/GrSurface.h"
16#include "src/gpu/mtl/GrMtlGpu.h"
17#include "src/gpu/mtl/GrMtlRenderTarget.h"
18#include "src/gpu/mtl/GrMtlTexture.h"
19#include "src/sksl/SkSLCompiler.h"
20
21#import <Metal/Metal.h>
22#ifdef SK_BUILD_FOR_IOS
23#import <UIKit/UIApplication.h>
24#endif
25
26#if !__has_feature(objc_arc)
27#error This file must be compiled with Arc. Use -fobjc-arc flag
28#endif
29
30GR_NORETAIN_BEGIN
31
32NSError* GrCreateMtlError(NSString* description, GrMtlErrorCode errorCode) {
33    NSDictionary* userInfo = [NSDictionary dictionaryWithObject:description
34                                                         forKey:NSLocalizedDescriptionKey];
35    return [NSError errorWithDomain:@"org.skia.ganesh"
36                               code:(NSInteger)errorCode
37                           userInfo:userInfo];
38}
39
40MTLTextureDescriptor* GrGetMTLTextureDescriptor(id<MTLTexture> mtlTexture) {
41    MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
42    texDesc.textureType = mtlTexture.textureType;
43    texDesc.pixelFormat = mtlTexture.pixelFormat;
44    texDesc.width = mtlTexture.width;
45    texDesc.height = mtlTexture.height;
46    texDesc.depth = mtlTexture.depth;
47    texDesc.mipmapLevelCount = mtlTexture.mipmapLevelCount;
48    texDesc.arrayLength = mtlTexture.arrayLength;
49    texDesc.sampleCount = mtlTexture.sampleCount;
50    if (@available(macOS 10.11, iOS 9.0, *)) {
51        texDesc.usage = mtlTexture.usage;
52    }
53    return texDesc;
54}
55
56// Print the source code for all shaders generated.
57static const bool gPrintSKSL = false;
58static const bool gPrintMSL = false;
59
60bool GrSkSLToMSL(const GrMtlGpu* gpu,
61                 const SkSL::String& sksl,
62                 SkSL::ProgramKind programKind,
63                 const SkSL::Program::Settings& settings,
64                 SkSL::String* msl,
65                 SkSL::Program::Inputs* outInputs,
66                 GrContextOptions::ShaderErrorHandler* errorHandler) {
67#ifdef SK_DEBUG
68    SkSL::String src = GrShaderUtils::PrettyPrint(sksl);
69#else
70    const SkSL::String& src = sksl;
71#endif
72    SkSL::Compiler* compiler = gpu->shaderCompiler();
73    std::unique_ptr<SkSL::Program> program =
74            gpu->shaderCompiler()->convertProgram(programKind,
75                                                  src,
76                                                  settings);
77    if (!program || !compiler->toMetal(*program, msl)) {
78        errorHandler->compileError(src.c_str(), compiler->errorText().c_str());
79        return false;
80    }
81
82    if (gPrintSKSL || gPrintMSL) {
83        GrShaderUtils::PrintShaderBanner(programKind);
84        if (gPrintSKSL) {
85            SkDebugf("SKSL:\n");
86            GrShaderUtils::PrintLineByLine(GrShaderUtils::PrettyPrint(sksl));
87        }
88        if (gPrintMSL) {
89            SkDebugf("MSL:\n");
90            GrShaderUtils::PrintLineByLine(GrShaderUtils::PrettyPrint(*msl));
91        }
92    }
93
94    *outInputs = program->fInputs;
95    return true;
96}
97
98id<MTLLibrary> GrCompileMtlShaderLibrary(const GrMtlGpu* gpu,
99                                         const SkSL::String& msl,
100                                         GrContextOptions::ShaderErrorHandler* errorHandler) {
101    TRACE_EVENT0("skia.shaders", "driver_compile_shader");
102    auto nsSource = [[NSString alloc] initWithBytesNoCopy:const_cast<char*>(msl.c_str())
103                                                   length:msl.size()
104                                                 encoding:NSUTF8StringEncoding
105                                             freeWhenDone:NO];
106    MTLCompileOptions* options = [[MTLCompileOptions alloc] init];
107    // array<> is supported in MSL 2.0 on MacOS 10.13+ and iOS 11+,
108    // and in MSL 1.2 on iOS 10+ (but not MacOS).
109    if (@available(macOS 10.13, iOS 11.0, *)) {
110        options.languageVersion = MTLLanguageVersion2_0;
111#if defined(SK_BUILD_FOR_IOS)
112    } else if (@available(macOS 10.12, iOS 10.0, *)) {
113        options.languageVersion = MTLLanguageVersion1_2;
114#endif
115    }
116    if (gpu->caps()->shaderCaps()->canUseFastMath()) {
117        options.fastMathEnabled = YES;
118    }
119
120    NSError* error = nil;
121#if defined(SK_BUILD_FOR_MAC)
122    id<MTLLibrary> compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), nsSource,
123                                                               options, &error);
124#else
125    id<MTLLibrary> compiledLibrary = [gpu->device() newLibraryWithSource:nsSource
126                                                                 options:options
127                                                                   error:&error];
128#endif
129    if (!compiledLibrary) {
130        errorHandler->compileError(msl.c_str(), error.debugDescription.UTF8String);
131        return nil;
132    }
133
134    return compiledLibrary;
135}
136
137void GrPrecompileMtlShaderLibrary(const GrMtlGpu* gpu,
138                                  const SkSL::String& msl) {
139    auto nsSource = [[NSString alloc] initWithBytesNoCopy:const_cast<char*>(msl.c_str())
140                                                   length:msl.size()
141                                                 encoding:NSUTF8StringEncoding
142                                             freeWhenDone:NO];
143    // Do nothing after completion for now.
144    // TODO: cache the result somewhere so we can use it later.
145    MTLNewLibraryCompletionHandler completionHandler =
146            ^(id<MTLLibrary> library, NSError* error) {};
147    [gpu->device() newLibraryWithSource:nsSource
148                                options:nil
149                      completionHandler:completionHandler];
150}
151
152// Wrapper to get atomic assignment for compiles and pipeline creation
153class MtlCompileResult : public SkRefCnt {
154public:
155    MtlCompileResult() : fCompiledObject(nil), fError(nil) {}
156    void set(id compiledObject, NSError* error) {
157        SkAutoMutexExclusive automutex(fMutex);
158        fCompiledObject = compiledObject;
159        fError = error;
160    }
161    std::pair<id, NSError*> get() {
162        SkAutoMutexExclusive automutex(fMutex);
163        return std::make_pair(fCompiledObject, fError);
164    }
165private:
166    SkMutex fMutex;
167    id fCompiledObject SK_GUARDED_BY(fMutex);
168    NSError* fError SK_GUARDED_BY(fMutex);
169};
170
171id<MTLLibrary> GrMtlNewLibraryWithSource(id<MTLDevice> device, NSString* mslCode,
172                                         MTLCompileOptions* options, NSError** error) {
173    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
174    sk_sp<MtlCompileResult> compileResult(new MtlCompileResult);
175    // We have to increment the ref for the Obj-C block manually because it won't do it for us
176    compileResult->ref();
177    MTLNewLibraryCompletionHandler completionHandler =
178            ^(id<MTLLibrary> library, NSError* compileError) {
179                compileResult->set(library, compileError);
180                dispatch_semaphore_signal(semaphore);
181                compileResult->unref();
182            };
183
184    [device newLibraryWithSource: mslCode
185                         options: options
186               completionHandler: completionHandler];
187
188    // Wait 1 second for the compiler
189    constexpr auto kTimeoutNS = 1000000000UL;
190    if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) {
191        if (error) {
192            constexpr auto kTimeoutMS = kTimeoutNS/1000000UL;
193            NSString* description =
194                    [NSString stringWithFormat:@"Compilation took longer than %lu ms",
195                                               kTimeoutMS];
196            *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout);
197        }
198        return nil;
199    }
200
201    id<MTLLibrary> compiledLibrary;
202    std::tie(compiledLibrary, *error) = compileResult->get();
203
204    return compiledLibrary;
205}
206
207id<MTLRenderPipelineState> GrMtlNewRenderPipelineStateWithDescriptor(
208        id<MTLDevice> device, MTLRenderPipelineDescriptor* pipelineDescriptor, NSError** error) {
209    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
210    sk_sp<MtlCompileResult> compileResult(new MtlCompileResult);
211    // We have to increment the ref for the Obj-C block manually because it won't do it for us
212    compileResult->ref();
213    MTLNewRenderPipelineStateCompletionHandler completionHandler =
214            ^(id<MTLRenderPipelineState> state, NSError* compileError) {
215                compileResult->set(state, compileError);
216                dispatch_semaphore_signal(semaphore);
217                compileResult->unref();
218            };
219
220    [device newRenderPipelineStateWithDescriptor: pipelineDescriptor
221                               completionHandler: completionHandler];
222
223    // Wait 1 second for pipeline creation
224    constexpr auto kTimeoutNS = 1000000000UL;
225    if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) {
226        if (error) {
227            constexpr auto kTimeoutMS = kTimeoutNS/1000000UL;
228            NSString* description =
229                    [NSString stringWithFormat:@"Pipeline creation took longer than %lu ms",
230                                               kTimeoutMS];
231            *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout);
232        }
233        return nil;
234    }
235
236    id<MTLRenderPipelineState> pipelineState;
237    std::tie(pipelineState, *error) = compileResult->get();
238
239    return pipelineState;
240}
241
242id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface) {
243    id<MTLTexture> mtlTexture = nil;
244
245    GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget());
246    GrMtlTexture* texture;
247    if (renderTarget) {
248        // We should not be using this for multisampled rendertargets with a separate resolve
249        // texture.
250        if (renderTarget->resolveAttachment()) {
251            SkASSERT(renderTarget->numSamples() > 1);
252            SkASSERT(false);
253            return nil;
254        }
255        mtlTexture = renderTarget->colorMTLTexture();
256    } else {
257        texture = static_cast<GrMtlTexture*>(surface->asTexture());
258        if (texture) {
259            mtlTexture = texture->mtlTexture();
260        }
261    }
262    return mtlTexture;
263}
264
265
266//////////////////////////////////////////////////////////////////////////////
267// CPP Utils
268
269GrMTLPixelFormat GrGetMTLPixelFormatFromMtlTextureInfo(const GrMtlTextureInfo& info) {
270    id<MTLTexture> GR_NORETAIN mtlTexture = GrGetMTLTexture(info.fTexture.get());
271    return static_cast<GrMTLPixelFormat>(mtlTexture.pixelFormat);
272}
273
274uint32_t GrMtlFormatChannels(GrMTLPixelFormat mtlFormat) {
275    switch (mtlFormat) {
276        case MTLPixelFormatRGBA8Unorm:      return kRGBA_SkColorChannelFlags;
277        case MTLPixelFormatR8Unorm:         return kRed_SkColorChannelFlag;
278        case MTLPixelFormatA8Unorm:         return kAlpha_SkColorChannelFlag;
279        case MTLPixelFormatBGRA8Unorm:      return kRGBA_SkColorChannelFlags;
280#if defined(SK_BUILD_FOR_IOS) && !TARGET_OS_SIMULATOR
281        case MTLPixelFormatB5G6R5Unorm:     return kRGB_SkColorChannelFlags;
282#endif
283        case MTLPixelFormatRGBA16Float:     return kRGBA_SkColorChannelFlags;
284        case MTLPixelFormatR16Float:        return kRed_SkColorChannelFlag;
285        case MTLPixelFormatRG8Unorm:        return kRG_SkColorChannelFlags;
286        case MTLPixelFormatRGB10A2Unorm:    return kRGBA_SkColorChannelFlags;
287#ifdef SK_BUILD_FOR_MAC
288        case MTLPixelFormatBGR10A2Unorm:    return kRGBA_SkColorChannelFlags;
289#endif
290#if defined(SK_BUILD_FOR_IOS) && !TARGET_OS_SIMULATOR
291        case MTLPixelFormatABGR4Unorm:      return kRGBA_SkColorChannelFlags;
292#endif
293        case MTLPixelFormatRGBA8Unorm_sRGB: return kRGBA_SkColorChannelFlags;
294        case MTLPixelFormatR16Unorm:        return kRed_SkColorChannelFlag;
295        case MTLPixelFormatRG16Unorm:       return kRG_SkColorChannelFlags;
296#ifdef SK_BUILD_FOR_IOS
297        case MTLPixelFormatETC2_RGB8:       return kRGB_SkColorChannelFlags;
298#else
299        case MTLPixelFormatBC1_RGBA:        return kRGBA_SkColorChannelFlags;
300#endif
301        case MTLPixelFormatRGBA16Unorm:     return kRGBA_SkColorChannelFlags;
302        case MTLPixelFormatRG16Float:       return kRG_SkColorChannelFlags;
303        case MTLPixelFormatStencil8:        return 0;
304
305        default:                            return 0;
306    }
307}
308
309GrColorFormatDesc GrMtlFormatDesc(GrMTLPixelFormat mtlFormat)  {
310    switch (mtlFormat) {
311        case MTLPixelFormatRGBA8Unorm:
312            return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kUnorm);
313        case MTLPixelFormatR8Unorm:
314            return GrColorFormatDesc::MakeR(8, GrColorTypeEncoding::kUnorm);
315        case MTLPixelFormatA8Unorm:
316            return GrColorFormatDesc::MakeAlpha(8, GrColorTypeEncoding::kUnorm);
317        case MTLPixelFormatBGRA8Unorm:
318            return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kUnorm);
319#if defined(SK_BUILD_FOR_IOS) && !TARGET_OS_SIMULATOR
320        case MTLPixelFormatB5G6R5Unorm:
321            return GrColorFormatDesc::MakeRGB(5, 6, 5, GrColorTypeEncoding::kUnorm);
322#endif
323        case MTLPixelFormatRGBA16Float:
324            return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kFloat);
325        case MTLPixelFormatR16Float:
326            return GrColorFormatDesc::MakeR(16, GrColorTypeEncoding::kFloat);
327        case MTLPixelFormatRG8Unorm:
328            return GrColorFormatDesc::MakeRG(8, GrColorTypeEncoding::kUnorm);
329        case MTLPixelFormatRGB10A2Unorm:
330            return GrColorFormatDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm);
331#ifdef SK_BUILD_FOR_MAC
332        case MTLPixelFormatBGR10A2Unorm:
333            return GrColorFormatDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm);
334#endif
335#if defined(SK_BUILD_FOR_IOS) && !TARGET_OS_SIMULATOR
336        case MTLPixelFormatABGR4Unorm:
337            return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm);
338#endif
339        case MTLPixelFormatRGBA8Unorm_sRGB:
340            return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kSRGBUnorm);
341        case MTLPixelFormatR16Unorm:
342            return GrColorFormatDesc::MakeR(16, GrColorTypeEncoding::kUnorm);
343        case MTLPixelFormatRG16Unorm:
344            return GrColorFormatDesc::MakeRG(16, GrColorTypeEncoding::kUnorm);
345        case MTLPixelFormatRGBA16Unorm:
346            return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kUnorm);
347        case MTLPixelFormatRG16Float:
348            return GrColorFormatDesc::MakeRG(16, GrColorTypeEncoding::kFloat);
349
350        // Compressed texture formats are not expected to have a description.
351#ifdef SK_BUILD_FOR_IOS
352        case MTLPixelFormatETC2_RGB8: return GrColorFormatDesc::MakeInvalid();
353#else
354        case MTLPixelFormatBC1_RGBA:  return GrColorFormatDesc::MakeInvalid();
355#endif
356
357        // This type only describes color channels.
358        case MTLPixelFormatStencil8: return GrColorFormatDesc::MakeInvalid();
359
360        default:
361            return GrColorFormatDesc::MakeInvalid();
362    }
363}
364
365SkImage::CompressionType GrMtlBackendFormatToCompressionType(const GrBackendFormat& format) {
366    MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
367    return GrMtlFormatToCompressionType(mtlFormat);
368}
369
370bool GrMtlFormatIsCompressed(MTLPixelFormat mtlFormat) {
371    switch (mtlFormat) {
372#ifdef SK_BUILD_FOR_IOS
373        case MTLPixelFormatETC2_RGB8:
374            return true;
375#else
376        case MTLPixelFormatBC1_RGBA:
377            return true;
378#endif
379        default:
380            return false;
381    }
382}
383
384SkImage::CompressionType GrMtlFormatToCompressionType(MTLPixelFormat mtlFormat) {
385    switch (mtlFormat) {
386#ifdef SK_BUILD_FOR_IOS
387        case MTLPixelFormatETC2_RGB8: return SkImage::CompressionType::kETC2_RGB8_UNORM;
388#else
389        case MTLPixelFormatBC1_RGBA:  return SkImage::CompressionType::kBC1_RGBA8_UNORM;
390#endif
391        default:                      return SkImage::CompressionType::kNone;
392    }
393
394    SkUNREACHABLE;
395}
396
397int GrMtlTextureInfoSampleCount(const GrMtlTextureInfo& info) {
398    id<MTLTexture> texture = GrGetMTLTexture(info.fTexture.get());
399    if (!texture) {
400        return 0;
401    }
402    return texture.sampleCount;
403}
404
405size_t GrMtlBackendFormatBytesPerBlock(const GrBackendFormat& format) {
406    MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
407    return GrMtlFormatBytesPerBlock(mtlFormat);
408}
409
410size_t GrMtlFormatBytesPerBlock(MTLPixelFormat mtlFormat) {
411    switch (mtlFormat) {
412        case MTLPixelFormatInvalid:         return 0;
413        case MTLPixelFormatRGBA8Unorm:      return 4;
414        case MTLPixelFormatR8Unorm:         return 1;
415        case MTLPixelFormatA8Unorm:         return 1;
416        case MTLPixelFormatBGRA8Unorm:      return 4;
417#ifdef SK_BUILD_FOR_IOS
418        case MTLPixelFormatB5G6R5Unorm:     return 2;
419#endif
420        case MTLPixelFormatRGBA16Float:     return 8;
421        case MTLPixelFormatR16Float:        return 2;
422        case MTLPixelFormatRG8Unorm:        return 2;
423        case MTLPixelFormatRGB10A2Unorm:    return 4;
424#ifdef SK_BUILD_FOR_MAC
425        case MTLPixelFormatBGR10A2Unorm:    return 4;
426#endif
427#ifdef SK_BUILD_FOR_IOS
428        case MTLPixelFormatABGR4Unorm:      return 2;
429#endif
430        case MTLPixelFormatRGBA8Unorm_sRGB: return 4;
431        case MTLPixelFormatR16Unorm:        return 2;
432        case MTLPixelFormatRG16Unorm:       return 4;
433#ifdef SK_BUILD_FOR_IOS
434        case MTLPixelFormatETC2_RGB8:       return 8;
435#else
436        case MTLPixelFormatBC1_RGBA:        return 8;
437#endif
438        case MTLPixelFormatRGBA16Unorm:     return 8;
439        case MTLPixelFormatRG16Float:       return 4;
440        case MTLPixelFormatStencil8:        return 1;
441
442        default:                            return 0;
443    }
444}
445
446int GrMtlBackendFormatStencilBits(const GrBackendFormat& format) {
447    MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
448    return GrMtlFormatStencilBits(mtlFormat);
449}
450
451int GrMtlFormatStencilBits(MTLPixelFormat mtlFormat) {
452    switch(mtlFormat) {
453     case MTLPixelFormatStencil8:
454         return 8;
455     default:
456         return 0;
457    }
458}
459
460#ifdef SK_BUILD_FOR_IOS
461bool GrMtlIsAppInBackground() {
462    return [NSThread isMainThread] &&
463           ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground);
464}
465#endif
466
467#if defined(SK_DEBUG) || GR_TEST_UTILS
468bool GrMtlFormatIsBGRA8(GrMTLPixelFormat mtlFormat) {
469    return mtlFormat == MTLPixelFormatBGRA8Unorm;
470}
471
472const char* GrMtlFormatToStr(GrMTLPixelFormat mtlFormat) {
473    switch (mtlFormat) {
474        case MTLPixelFormatInvalid:         return "Invalid";
475        case MTLPixelFormatRGBA8Unorm:      return "RGBA8Unorm";
476        case MTLPixelFormatR8Unorm:         return "R8Unorm";
477        case MTLPixelFormatA8Unorm:         return "A8Unorm";
478        case MTLPixelFormatBGRA8Unorm:      return "BGRA8Unorm";
479#ifdef SK_BUILD_FOR_IOS
480        case MTLPixelFormatB5G6R5Unorm:     return "B5G6R5Unorm";
481#endif
482        case MTLPixelFormatRGBA16Float:     return "RGBA16Float";
483        case MTLPixelFormatR16Float:        return "R16Float";
484        case MTLPixelFormatRG8Unorm:        return "RG8Unorm";
485        case MTLPixelFormatRGB10A2Unorm:    return "RGB10A2Unorm";
486#ifdef SK_BUILD_FOR_MAC
487        case MTLPixelFormatBGR10A2Unorm:    return "BGR10A2Unorm";
488#endif
489#ifdef SK_BUILD_FOR_IOS
490        case MTLPixelFormatABGR4Unorm:      return "ABGR4Unorm";
491#endif
492        case MTLPixelFormatRGBA8Unorm_sRGB: return "RGBA8Unorm_sRGB";
493        case MTLPixelFormatR16Unorm:        return "R16Unorm";
494        case MTLPixelFormatRG16Unorm:       return "RG16Unorm";
495#ifdef SK_BUILD_FOR_IOS
496        case MTLPixelFormatETC2_RGB8:       return "ETC2_RGB8";
497#else
498        case MTLPixelFormatBC1_RGBA:        return "BC1_RGBA";
499#endif
500        case MTLPixelFormatRGBA16Unorm:     return "RGBA16Unorm";
501        case MTLPixelFormatRG16Float:       return "RG16Float";
502        case MTLPixelFormatStencil8:        return "Stencil8";
503
504        default:                            return "Unknown";
505    }
506}
507
508#endif
509
510GR_NORETAIN_END
511