xref: /aosp_15_r20/external/skia/src/gpu/ganesh/mtl/GrMtlUtil.mm (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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#import <Metal/Metal.h>
11
12#include "include/core/SkTextureCompressionType.h"
13#include "include/gpu/ganesh/GrBackendSurface.h"
14#include "include/private/base/SkMutex.h"
15#include "include/private/gpu/ganesh/GrTypesPriv.h"
16#include "src/core/SkTraceEvent.h"
17#include "src/gpu/ganesh/GrSurface.h"
18#include "src/gpu/ganesh/mtl/GrMtlGpu.h"
19#include "src/gpu/ganesh/mtl/GrMtlRenderTarget.h"
20#include "src/gpu/ganesh/mtl/GrMtlTexture.h"
21
22#if !__has_feature(objc_arc)
23#error This file must be compiled with Arc. Use -fobjc-arc flag
24#endif
25
26GR_NORETAIN_BEGIN
27
28NSError* GrCreateMtlError(NSString* description, GrMtlErrorCode errorCode) {
29    NSDictionary* userInfo = [NSDictionary dictionaryWithObject:description
30                                                         forKey:NSLocalizedDescriptionKey];
31    return [NSError errorWithDomain:@"org.skia.ganesh"
32                               code:(NSInteger)errorCode
33                           userInfo:userInfo];
34}
35
36MTLTextureDescriptor* GrGetMTLTextureDescriptor(id<MTLTexture> mtlTexture) {
37    MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
38    texDesc.textureType = mtlTexture.textureType;
39    texDesc.pixelFormat = mtlTexture.pixelFormat;
40    texDesc.width = mtlTexture.width;
41    texDesc.height = mtlTexture.height;
42    texDesc.depth = mtlTexture.depth;
43    texDesc.mipmapLevelCount = mtlTexture.mipmapLevelCount;
44    texDesc.arrayLength = mtlTexture.arrayLength;
45    texDesc.sampleCount = mtlTexture.sampleCount;
46    if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) {
47        texDesc.usage = mtlTexture.usage;
48    }
49    return texDesc;
50}
51
52id<MTLLibrary> GrCompileMtlShaderLibrary(const GrMtlGpu* gpu,
53                                         const std::string& msl,
54                                         GrContextOptions::ShaderErrorHandler* errorHandler) {
55    TRACE_EVENT0("skia.shaders", "driver_compile_shader");
56    NSString* nsSource = [[NSString alloc] initWithBytesNoCopy:const_cast<char*>(msl.c_str())
57                                                        length:msl.size()
58                                                      encoding:NSUTF8StringEncoding
59                                                  freeWhenDone:NO];
60    if (!nsSource) {
61        return nil;
62    }
63    MTLCompileOptions* options = [[MTLCompileOptions alloc] init];
64    // array<> is supported in MSL 2.0 on MacOS 10.13+ and iOS 11+,
65    // and in MSL 1.2 on iOS 10+ (but not MacOS).
66    if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
67        options.languageVersion = MTLLanguageVersion2_0;
68#if defined(SK_BUILD_FOR_IOS)
69    } else if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) {
70        options.languageVersion = MTLLanguageVersion1_2;
71#endif
72    }
73    options.fastMathEnabled = YES;
74
75    NSError* error = nil;
76    id<MTLLibrary> compiledLibrary;
77    if (@available(macOS 10.15, *)) {
78        compiledLibrary = [gpu->device() newLibraryWithSource:(NSString* _Nonnull)nsSource
79                                                      options:options
80                                                        error:&error];
81    } else {
82        compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), (NSString* _Nonnull)nsSource,
83                                                    options, &error);
84    }
85    if (!compiledLibrary) {
86        errorHandler->compileError(
87                msl.c_str(), error.debugDescription.UTF8String, /*shaderWasCached=*/false);
88        return nil;
89    }
90
91    return compiledLibrary;
92}
93
94void GrPrecompileMtlShaderLibrary(const GrMtlGpu* gpu,
95                                  const std::string& msl) {
96    NSString* nsSource = [[NSString alloc] initWithBytesNoCopy:const_cast<char*>(msl.c_str())
97                                                        length:msl.size()
98                                                      encoding:NSUTF8StringEncoding
99                                                  freeWhenDone:NO];
100    if (!nsSource) {
101        return;
102    }
103    // Do nothing after completion for now.
104    // TODO: cache the result somewhere so we can use it later.
105    MTLNewLibraryCompletionHandler completionHandler = ^(id<MTLLibrary> library, NSError* error) {};
106    [gpu->device() newLibraryWithSource:(NSString* _Nonnull)nsSource
107                                options:nil
108                      completionHandler:completionHandler];
109}
110
111// Wrapper to get atomic assignment for compiles and pipeline creation
112class MtlCompileResult : public SkRefCnt {
113public:
114    MtlCompileResult() : fCompiledObject(nil), fError(nil) {}
115    void set(id compiledObject, NSError* error) {
116        SkAutoMutexExclusive automutex(fMutex);
117        fCompiledObject = compiledObject;
118        fError = error;
119    }
120    std::pair<id, NSError*> get() {
121        SkAutoMutexExclusive automutex(fMutex);
122        return std::make_pair(fCompiledObject, fError);
123    }
124private:
125    SkMutex fMutex;
126    id fCompiledObject SK_GUARDED_BY(fMutex);
127    NSError* fError SK_GUARDED_BY(fMutex);
128};
129
130id<MTLLibrary> GrMtlNewLibraryWithSource(id<MTLDevice> device, NSString* mslCode,
131                                         MTLCompileOptions* options, NSError** error) {
132    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
133    sk_sp<MtlCompileResult> compileResult(new MtlCompileResult);
134    // We have to increment the ref for the Obj-C block manually because it won't do it for us
135    compileResult->ref();
136    MTLNewLibraryCompletionHandler completionHandler =
137            ^(id<MTLLibrary> library, NSError* compileError) {
138                compileResult->set(library, compileError);
139                dispatch_semaphore_signal(semaphore);
140                compileResult->unref();
141            };
142
143    [device newLibraryWithSource: mslCode
144                         options: options
145               completionHandler: completionHandler];
146
147    // Wait 1 second for the compiler
148    constexpr auto kTimeoutNS = 1000000000UL;
149    if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) {
150        if (error) {
151            constexpr auto kTimeoutMS = kTimeoutNS/1000000UL;
152            NSString* description =
153                    [NSString stringWithFormat:@"Compilation took longer than %lu ms",
154                                               kTimeoutMS];
155            *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout);
156        }
157        return nil;
158    }
159
160    id<MTLLibrary> compiledLibrary;
161    std::tie(compiledLibrary, *error) = compileResult->get();
162
163    return compiledLibrary;
164}
165
166id<MTLRenderPipelineState> GrMtlNewRenderPipelineStateWithDescriptor(
167        id<MTLDevice> device, MTLRenderPipelineDescriptor* pipelineDescriptor, NSError** error) {
168    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
169    sk_sp<MtlCompileResult> compileResult(new MtlCompileResult);
170    // We have to increment the ref for the Obj-C block manually because it won't do it for us
171    compileResult->ref();
172    MTLNewRenderPipelineStateCompletionHandler completionHandler =
173            ^(id<MTLRenderPipelineState> state, NSError* compileError) {
174                compileResult->set(state, compileError);
175                dispatch_semaphore_signal(semaphore);
176                compileResult->unref();
177            };
178
179    [device newRenderPipelineStateWithDescriptor: pipelineDescriptor
180                               completionHandler: completionHandler];
181
182    // Wait 1 second for pipeline creation
183    constexpr auto kTimeoutNS = 1000000000UL;
184    if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) {
185        if (error) {
186            constexpr auto kTimeoutMS = kTimeoutNS/1000000UL;
187            NSString* description =
188                    [NSString stringWithFormat:@"Pipeline creation took longer than %lu ms",
189                                               kTimeoutMS];
190            *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout);
191        }
192        return nil;
193    }
194
195    id<MTLRenderPipelineState> pipelineState;
196    std::tie(pipelineState, *error) = compileResult->get();
197
198    return pipelineState;
199}
200
201id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface) {
202    id<MTLTexture> mtlTexture = nil;
203
204    GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget());
205    GrMtlTexture* texture;
206    if (renderTarget) {
207        // We should not be using this for multisampled rendertargets with a separate resolve
208        // texture.
209        if (renderTarget->resolveAttachment()) {
210            SkASSERT(renderTarget->numSamples() > 1);
211            SkASSERT(false);
212            return nil;
213        }
214        mtlTexture = renderTarget->colorMTLTexture();
215    } else {
216        texture = static_cast<GrMtlTexture*>(surface->asTexture());
217        if (texture) {
218            mtlTexture = texture->mtlTexture();
219        }
220    }
221    return mtlTexture;
222}
223
224
225//////////////////////////////////////////////////////////////////////////////
226// CPP Utils
227
228GrMTLPixelFormat GrGetMTLPixelFormatFromMtlTextureInfo(const GrMtlTextureInfo& info) {
229    id<MTLTexture> GR_NORETAIN mtlTexture = GrGetMTLTexture(info.fTexture.get());
230    return static_cast<GrMTLPixelFormat>(mtlTexture.pixelFormat);
231}
232
233GrColorFormatDesc GrMtlFormatDesc(MTLPixelFormat mtlFormat) {
234    switch (mtlFormat) {
235        case MTLPixelFormatRGBA8Unorm:
236            return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kUnorm);
237        case MTLPixelFormatR8Unorm:
238            return GrColorFormatDesc::MakeR(8, GrColorTypeEncoding::kUnorm);
239        case MTLPixelFormatA8Unorm:
240            return GrColorFormatDesc::MakeAlpha(8, GrColorTypeEncoding::kUnorm);
241        case MTLPixelFormatBGRA8Unorm:
242            return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kUnorm);
243        case MTLPixelFormatB5G6R5Unorm:
244            return GrColorFormatDesc::MakeRGB(5, 6, 5, GrColorTypeEncoding::kUnorm);
245        case MTLPixelFormatRGBA16Float:
246            return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kFloat);
247        case MTLPixelFormatR16Float:
248            return GrColorFormatDesc::MakeR(16, GrColorTypeEncoding::kFloat);
249        case MTLPixelFormatRG8Unorm:
250            return GrColorFormatDesc::MakeRG(8, GrColorTypeEncoding::kUnorm);
251        case MTLPixelFormatRGB10A2Unorm:
252            return GrColorFormatDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm);
253        case MTLPixelFormatBGR10A2Unorm:
254            return GrColorFormatDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm);
255        case MTLPixelFormatABGR4Unorm:
256            return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm);
257        case MTLPixelFormatRGBA8Unorm_sRGB:
258            return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kSRGBUnorm);
259        case MTLPixelFormatR16Unorm:
260            return GrColorFormatDesc::MakeR(16, GrColorTypeEncoding::kUnorm);
261        case MTLPixelFormatRG16Unorm:
262            return GrColorFormatDesc::MakeRG(16, GrColorTypeEncoding::kUnorm);
263        case MTLPixelFormatRGBA16Unorm:
264            return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kUnorm);
265        case MTLPixelFormatRG16Float:
266            return GrColorFormatDesc::MakeRG(16, GrColorTypeEncoding::kFloat);
267
268        // Compressed texture formats are not expected to have a description.
269        case MTLPixelFormatETC2_RGB8: return GrColorFormatDesc::MakeInvalid();
270#ifdef SK_BUILD_FOR_MAC
271        case MTLPixelFormatBC1_RGBA:  return GrColorFormatDesc::MakeInvalid();
272#endif
273
274        // This type only describes color channels.
275        case MTLPixelFormatStencil8: return GrColorFormatDesc::MakeInvalid();
276
277        default:
278            return GrColorFormatDesc::MakeInvalid();
279    }
280}
281
282SkTextureCompressionType GrMtlFormatToCompressionType(MTLPixelFormat format) {
283    switch (format) {
284        case MTLPixelFormatETC2_RGB8: return SkTextureCompressionType::kETC2_RGB8_UNORM;
285#ifdef SK_BUILD_FOR_MAC
286        case MTLPixelFormatBC1_RGBA:  return SkTextureCompressionType::kBC1_RGBA8_UNORM;
287#endif
288        default:                      return SkTextureCompressionType::kNone;
289    }
290
291    SkUNREACHABLE;
292}
293
294int GrMtlTextureInfoSampleCount(const GrMtlTextureInfo& info) {
295    id<MTLTexture> texture = GrGetMTLTexture(info.fTexture.get());
296    if (!texture) {
297        return 0;
298    }
299    return texture.sampleCount;
300}
301
302int GrMtlFormatStencilBits(MTLPixelFormat format) {
303    switch (format) {
304        case MTLPixelFormatStencil8:
305            return 8;
306        default:
307            return 0;
308    }
309}
310
311#if defined(SK_DEBUG) || defined(GPU_TEST_UTILS)
312bool GrMtlFormatIsBGRA8(GrMTLPixelFormat mtlFormat) {
313    return mtlFormat == MTLPixelFormatBGRA8Unorm;
314}
315#endif
316
317GR_NORETAIN_END
318