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