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/GrSurface.h"
11#include "include/private/GrTypesPriv.h"
12#include "src/gpu/mtl/GrMtlGpu.h"
13#include "src/gpu/mtl/GrMtlRenderTarget.h"
14#include "src/gpu/mtl/GrMtlTexture.h"
15#include "src/sksl/SkSLCompiler.h"
16
17#import <Metal/Metal.h>
18
19#if !__has_feature(objc_arc)
20#error This file must be compiled with Arc. Use -fobjc-arc flag
21#endif
22
23#define PRINT_MSL 0 // print out the MSL code generated
24
25bool GrPixelConfigToMTLFormat(GrPixelConfig config, MTLPixelFormat* format) {
26    MTLPixelFormat dontCare;
27    if (!format) {
28        format = &dontCare;
29    }
30
31    switch (config) {
32        case kUnknown_GrPixelConfig:
33            return false;
34        case kRGBA_8888_GrPixelConfig:
35            *format = MTLPixelFormatRGBA8Unorm;
36            return true;
37        case kRGB_888_GrPixelConfig:
38            *format = MTLPixelFormatRGBA8Unorm;
39            return true;
40        case kRGB_888X_GrPixelConfig:
41            *format = MTLPixelFormatRGBA8Unorm;
42            return true;
43        case kRG_88_GrPixelConfig:
44            *format = MTLPixelFormatRG8Unorm;
45            return true;
46        case kBGRA_8888_GrPixelConfig:
47            *format = MTLPixelFormatBGRA8Unorm;
48            return true;
49        case kSRGBA_8888_GrPixelConfig:
50            *format = MTLPixelFormatRGBA8Unorm_sRGB;
51            return true;
52        case kRGBA_1010102_GrPixelConfig:
53            *format = MTLPixelFormatRGB10A2Unorm;
54            return true;
55        case kRGB_565_GrPixelConfig:
56#ifdef SK_BUILD_FOR_IOS
57            *format = MTLPixelFormatB5G6R5Unorm;
58            return true;
59#else
60            return false;
61#endif
62        case kRGBA_4444_GrPixelConfig:
63#ifdef SK_BUILD_FOR_IOS
64            *format = MTLPixelFormatABGR4Unorm;
65            return true;
66#else
67            return false;
68#endif
69        case kAlpha_8_GrPixelConfig: // fall through
70        case kAlpha_8_as_Red_GrPixelConfig:
71            *format = MTLPixelFormatR8Unorm;
72            return true;
73        case kAlpha_8_as_Alpha_GrPixelConfig:
74            *format = MTLPixelFormatA8Unorm;
75            return true;
76        case kGray_8_GrPixelConfig: // fall through
77        case kGray_8_as_Red_GrPixelConfig:
78            *format = MTLPixelFormatR8Unorm;
79            return true;
80        case kGray_8_as_Lum_GrPixelConfig:
81            return false;
82        case kRGBA_half_GrPixelConfig:
83            *format = MTLPixelFormatRGBA16Float;
84            return true;
85        case kRGBA_half_Clamped_GrPixelConfig:
86            *format = MTLPixelFormatRGBA16Float;
87            return true;
88        case kAlpha_half_GrPixelConfig: // fall through
89        case kAlpha_half_as_Red_GrPixelConfig:
90            *format = MTLPixelFormatR16Float;
91            return true;
92        case kAlpha_half_as_Lum_GrPixelConfig:
93            return false;
94        case kRGB_ETC1_GrPixelConfig:
95#ifdef SK_BUILD_FOR_IOS
96            *format = MTLPixelFormatETC2_RGB8;
97            return true;
98#else
99            return false;
100#endif
101        case kAlpha_16_GrPixelConfig:
102            *format = MTLPixelFormatR16Unorm;
103            return true;
104        case kRG_1616_GrPixelConfig:
105            *format = MTLPixelFormatRG16Unorm;
106            return true;
107        case kRGBA_16161616_GrPixelConfig:
108            *format = MTLPixelFormatRGBA16Unorm;
109            return true;
110        case kRG_half_GrPixelConfig:
111            *format = MTLPixelFormatRG16Float;
112            return true;
113    }
114    SK_ABORT("Unexpected config");
115}
116
117MTLTextureDescriptor* GrGetMTLTextureDescriptor(id<MTLTexture> mtlTexture) {
118    MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
119    texDesc.textureType = mtlTexture.textureType;
120    texDesc.pixelFormat = mtlTexture.pixelFormat;
121    texDesc.width = mtlTexture.width;
122    texDesc.height = mtlTexture.height;
123    texDesc.depth = mtlTexture.depth;
124    texDesc.mipmapLevelCount = mtlTexture.mipmapLevelCount;
125    texDesc.arrayLength = mtlTexture.arrayLength;
126    texDesc.sampleCount = mtlTexture.sampleCount;
127    if (@available(macOS 10.11, iOS 9.0, *)) {
128        texDesc.usage = mtlTexture.usage;
129    }
130    return texDesc;
131}
132
133#if PRINT_MSL
134void print_msl(const char* source) {
135    SkTArray<SkString> lines;
136    SkStrSplit(source, "\n", kStrict_SkStrSplitMode, &lines);
137    for (int i = 0; i < lines.count(); i++) {
138        SkString& line = lines[i];
139        line.prependf("%4i\t", i + 1);
140        SkDebugf("%s\n", line.c_str());
141    }
142}
143#endif
144
145id<MTLLibrary> GrCompileMtlShaderLibrary(const GrMtlGpu* gpu,
146                                         const char* shaderString,
147                                         SkSL::Program::Kind kind,
148                                         const SkSL::Program::Settings& settings,
149                                         SkSL::Program::Inputs* outInputs) {
150    std::unique_ptr<SkSL::Program> program =
151            gpu->shaderCompiler()->convertProgram(kind,
152                                                  SkSL::String(shaderString),
153                                                  settings);
154
155    if (!program) {
156        SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str());
157        SkASSERT(false);
158        return nil;
159    }
160
161    *outInputs = program->fInputs;
162    SkSL::String code;
163    if (!gpu->shaderCompiler()->toMetal(*program, &code)) {
164        SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
165        SkASSERT(false);
166        return nil;
167    }
168    NSString* mtlCode = [[NSString alloc] initWithCString: code.c_str()
169                                                 encoding: NSASCIIStringEncoding];
170#if PRINT_MSL
171    print_msl([mtlCode cStringUsingEncoding: NSASCIIStringEncoding]);
172#endif
173
174    MTLCompileOptions* defaultOptions = [[MTLCompileOptions alloc] init];
175#if defined(SK_BUILD_FOR_MAC) && defined(GR_USE_COMPLETION_HANDLER)
176    bool timedout;
177    id<MTLLibrary> compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), mtlCode,
178                                                               defaultOptions, &timedout);
179    if (timedout) {
180        // try again
181        compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), mtlCode,
182                                                    defaultOptions, &timedout);
183    }
184#else
185    NSError* error = nil;
186    id<MTLLibrary> compiledLibrary = [gpu->device() newLibraryWithSource: mtlCode
187                                                                 options: defaultOptions
188                                                                   error: &error];
189    if (error) {
190        SkDebugf("Error compiling MSL shader: %s\n%s\n",
191                 code.c_str(),
192                 [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
193        return nil;
194    }
195#endif
196    return compiledLibrary;
197}
198
199id<MTLLibrary> GrMtlNewLibraryWithSource(id<MTLDevice> device, NSString* mslCode,
200                                         MTLCompileOptions* options, bool* timedout) {
201    dispatch_semaphore_t compilerSemaphore = dispatch_semaphore_create(0);
202
203    __block dispatch_semaphore_t semaphore = compilerSemaphore;
204    __block id<MTLLibrary> compiledLibrary;
205    [device newLibraryWithSource: mslCode
206                         options: options
207               completionHandler:
208        ^(id<MTLLibrary> library, NSError* error) {
209            if (error) {
210                SkDebugf("Error compiling MSL shader: %s\n%s\n",
211                    mslCode,
212                    [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
213            }
214            compiledLibrary = library;
215            dispatch_semaphore_signal(semaphore);
216        }
217    ];
218
219    // Wait 100 ms for the compiler
220    if (dispatch_semaphore_wait(compilerSemaphore, dispatch_time(DISPATCH_TIME_NOW, 100000))) {
221        SkDebugf("Timeout compiling MSL shader\n");
222        *timedout = true;
223        return nil;
224    }
225
226    *timedout = false;
227    return compiledLibrary;
228}
229
230id<MTLRenderPipelineState> GrMtlNewRenderPipelineStateWithDescriptor(
231        id<MTLDevice> device, MTLRenderPipelineDescriptor* pipelineDescriptor, bool* timedout) {
232    dispatch_semaphore_t pipelineSemaphore = dispatch_semaphore_create(0);
233
234    __block dispatch_semaphore_t semaphore = pipelineSemaphore;
235    __block id<MTLRenderPipelineState> pipelineState;
236    [device newRenderPipelineStateWithDescriptor: pipelineDescriptor
237                               completionHandler:
238        ^(id<MTLRenderPipelineState> state, NSError* error) {
239            if (error) {
240                SkDebugf("Error creating pipeline: %s\n",
241                    [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
242            }
243            pipelineState = state;
244            dispatch_semaphore_signal(semaphore);
245        }
246     ];
247
248    // Wait 500 ms for pipeline creation
249    if (dispatch_semaphore_wait(pipelineSemaphore, dispatch_time(DISPATCH_TIME_NOW, 500000))) {
250        SkDebugf("Timeout creating pipeline.\n");
251        *timedout = true;
252        return nil;
253    }
254
255    *timedout = false;
256    return pipelineState;
257}
258
259id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface) {
260    id<MTLTexture> mtlTexture = nil;
261
262    GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget());
263    GrMtlTexture* texture;
264    if (renderTarget) {
265        // We should not be using this for multisampled rendertargets
266        if (renderTarget->numSamples() > 1) {
267            SkASSERT(false);
268            return nil;
269        }
270        mtlTexture = renderTarget->mtlColorTexture();
271    } else {
272        texture = static_cast<GrMtlTexture*>(surface->asTexture());
273        if (texture) {
274            mtlTexture = texture->mtlTexture();
275        }
276    }
277    return mtlTexture;
278}
279
280
281//////////////////////////////////////////////////////////////////////////////
282// CPP Utils
283
284GrMTLPixelFormat GrGetMTLPixelFormatFromMtlTextureInfo(const GrMtlTextureInfo& info) {
285    id<MTLTexture> mtlTexture = GrGetMTLTexture(info.fTexture.get());
286    return static_cast<GrMTLPixelFormat>(mtlTexture.pixelFormat);
287}
288
289bool GrMtlFormatIsCompressed(MTLPixelFormat mtlFormat) {
290    switch (mtlFormat) {
291#ifdef SK_BUILD_FOR_IOS
292        case MTLPixelFormatETC2_RGB8:
293            return true;
294#endif
295        default:
296            return false;
297    }
298}
299
300bool GrMtlFormatToCompressionType(MTLPixelFormat mtlFormat,
301                                  SkImage::CompressionType* compressionType) {
302    switch (mtlFormat) {
303#ifdef SK_BUILD_FOR_IOS
304        case MTLPixelFormatETC2_RGB8:
305            *compressionType = SkImage::kETC1_CompressionType;
306            return true;
307#endif
308        default:
309            return false;
310    }
311}
312
313#if GR_TEST_UTILS
314bool GrMtlFormatIsBGRA(GrMTLPixelFormat mtlFormat) {
315    return mtlFormat == MTLPixelFormatBGRA8Unorm;
316}
317
318const char* GrMtlFormatToStr(GrMTLPixelFormat mtlFormat) {
319    switch (mtlFormat) {
320        case MTLPixelFormatInvalid:         return "Invalid";
321        case MTLPixelFormatRGBA8Unorm:      return "RGBA8Unorm";
322        case MTLPixelFormatR8Unorm:         return "R8Unorm";
323        case MTLPixelFormatA8Unorm:         return "A8Unorm";
324        case MTLPixelFormatBGRA8Unorm:      return "BGRA8Unorm";
325#ifdef SK_BUILD_FOR_IOS
326        case MTLPixelFormatB5G6R5Unorm:     return "B5G6R5Unorm";
327#endif
328        case MTLPixelFormatRGBA16Float:     return "RGBA16Float";
329        case MTLPixelFormatR16Float:        return "R16Float";
330        case MTLPixelFormatRG8Unorm:        return "RG8Unorm";
331        case MTLPixelFormatRGB10A2Unorm:    return "RGB10A2Unorm";
332#ifdef SK_BUILD_FOR_IOS
333        case MTLPixelFormatABGR4Unorm:      return "ABGR4Unorm";
334#endif
335        case MTLPixelFormatRGBA8Unorm_sRGB: return "RGBA8Unorm_sRGB";
336        case MTLPixelFormatR16Unorm:        return "R16Unorm";
337        case MTLPixelFormatRG16Unorm:       return "RG16Unorm";
338#ifdef SK_BUILD_FOR_IOS
339        case MTLPixelFormatETC2_RGB8:      return "ETC2_RGB8";
340#endif
341        case MTLPixelFormatRGBA16Unorm:    return "RGBA16Unorm";
342        case MTLPixelFormatRG16Float:      return "RG16Float";
343
344        default:                           return "Unknown";
345    }
346}
347
348#endif
349
350
351
352