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