2 * Copyright 2017 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "src/gpu/ganesh/mtl/GrMtlUtil.h"
10 #include "include/gpu/GrBackendSurface.h"
11 #include "include/private/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/utils/SkShaderUtils.h"
21 #import <Metal/Metal.h>
22 #ifdef SK_BUILD_FOR_IOS
23 #import <UIKit/UIApplication.h>
26 #if !__has_feature(objc_arc)
27 #error This file must be compiled with Arc. Use -fobjc-arc flag
32 NSError* 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
40 MTLTextureDescriptor* 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;
56 // Print the source code for all shaders generated.
57 static const bool gPrintSKSL = false;
58 static const bool gPrintMSL = false;
60 bool GrSkSLToMSL(const GrMtlGpu* gpu,
61 const std::string& sksl,
62 SkSL::ProgramKind programKind,
63 const SkSL::Program::Settings& settings,
65 SkSL::Program::Inputs* outInputs,
66 GrContextOptions::ShaderErrorHandler* errorHandler) {
68 std::string src = SkShaderUtils::PrettyPrint(sksl);
70 const std::string& src = sksl;
72 SkSL::Compiler* compiler = gpu->shaderCompiler();
73 std::unique_ptr<SkSL::Program> program =
74 gpu->shaderCompiler()->convertProgram(programKind,
77 if (!program || !compiler->toMetal(*program, msl)) {
78 errorHandler->compileError(src.c_str(), compiler->errorText().c_str());
82 if (gPrintSKSL || gPrintMSL) {
83 SkShaderUtils::PrintShaderBanner(programKind);
86 SkShaderUtils::PrintLineByLine(SkShaderUtils::PrettyPrint(sksl));
90 SkShaderUtils::PrintLineByLine(SkShaderUtils::PrettyPrint(*msl));
94 *outInputs = program->fInputs;
98 id<MTLLibrary> GrCompileMtlShaderLibrary(const GrMtlGpu* gpu,
99 const std::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())
104 encoding:NSUTF8StringEncoding
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;
116 if (gpu->caps()->shaderCaps()->canUseFastMath()) {
117 options.fastMathEnabled = YES;
120 NSError* error = nil;
121 #if defined(SK_BUILD_FOR_MAC)
122 id<MTLLibrary> compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), nsSource,
125 id<MTLLibrary> compiledLibrary = [gpu->device() newLibraryWithSource:nsSource
129 if (!compiledLibrary) {
130 errorHandler->compileError(msl.c_str(), error.debugDescription.UTF8String);
134 return compiledLibrary;
137 void GrPrecompileMtlShaderLibrary(const GrMtlGpu* gpu,
138 const std::string& msl) {
139 auto nsSource = [[NSString alloc] initWithBytesNoCopy:const_cast<char*>(msl.c_str())
141 encoding:NSUTF8StringEncoding
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
149 completionHandler:completionHandler];
152 // Wrapper to get atomic assignment for compiles and pipeline creation
153 class MtlCompileResult : public SkRefCnt {
155 MtlCompileResult() : fCompiledObject(nil), fError(nil) {}
156 void set(id compiledObject, NSError* error) {
157 SkAutoMutexExclusive automutex(fMutex);
158 fCompiledObject = compiledObject;
161 std::pair<id, NSError*> get() {
162 SkAutoMutexExclusive automutex(fMutex);
163 return std::make_pair(fCompiledObject, fError);
167 id fCompiledObject SK_GUARDED_BY(fMutex);
168 NSError* fError SK_GUARDED_BY(fMutex);
171 id<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();
184 [device newLibraryWithSource: mslCode
186 completionHandler: completionHandler];
188 // Wait 1 second for the compiler
189 constexpr auto kTimeoutNS = 1000000000UL;
190 if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) {
192 constexpr auto kTimeoutMS = kTimeoutNS/1000000UL;
193 NSString* description =
194 [NSString stringWithFormat:@"Compilation took longer than %lu ms",
196 *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout);
201 id<MTLLibrary> compiledLibrary;
202 std::tie(compiledLibrary, *error) = compileResult->get();
204 return compiledLibrary;
207 id<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();
220 [device newRenderPipelineStateWithDescriptor: pipelineDescriptor
221 completionHandler: completionHandler];
223 // Wait 1 second for pipeline creation
224 constexpr auto kTimeoutNS = 1000000000UL;
225 if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) {
227 constexpr auto kTimeoutMS = kTimeoutNS/1000000UL;
228 NSString* description =
229 [NSString stringWithFormat:@"Pipeline creation took longer than %lu ms",
231 *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout);
236 id<MTLRenderPipelineState> pipelineState;
237 std::tie(pipelineState, *error) = compileResult->get();
239 return pipelineState;
242 id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface) {
243 id<MTLTexture> mtlTexture = nil;
245 GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget());
246 GrMtlTexture* texture;
248 // We should not be using this for multisampled rendertargets with a separate resolve
250 if (renderTarget->resolveAttachment()) {
251 SkASSERT(renderTarget->numSamples() > 1);
255 mtlTexture = renderTarget->colorMTLTexture();
257 texture = static_cast<GrMtlTexture*>(surface->asTexture());
259 mtlTexture = texture->mtlTexture();
266 //////////////////////////////////////////////////////////////////////////////
269 GrMTLPixelFormat GrGetMTLPixelFormatFromMtlTextureInfo(const GrMtlTextureInfo& info) {
270 id<MTLTexture> GR_NORETAIN mtlTexture = GrGetMTLTexture(info.fTexture.get());
271 return static_cast<GrMTLPixelFormat>(mtlTexture.pixelFormat);
274 uint32_t GrMtlFormatChannels(GrMTLPixelFormat 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;
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;
290 #if defined(SK_BUILD_FOR_IOS) && !TARGET_OS_SIMULATOR
291 case MTLPixelFormatABGR4Unorm: return kRGBA_SkColorChannelFlags;
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;
299 case MTLPixelFormatBC1_RGBA: return kRGBA_SkColorChannelFlags;
301 case MTLPixelFormatRGBA16Unorm: return kRGBA_SkColorChannelFlags;
302 case MTLPixelFormatRG16Float: return kRG_SkColorChannelFlags;
303 case MTLPixelFormatStencil8: return 0;
309 GrColorFormatDesc GrMtlFormatDesc(GrMTLPixelFormat 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);
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);
335 #if defined(SK_BUILD_FOR_IOS) && !TARGET_OS_SIMULATOR
336 case MTLPixelFormatABGR4Unorm:
337 return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm);
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);
350 // Compressed texture formats are not expected to have a description.
351 #ifdef SK_BUILD_FOR_IOS
352 case MTLPixelFormatETC2_RGB8: return GrColorFormatDesc::MakeInvalid();
354 case MTLPixelFormatBC1_RGBA: return GrColorFormatDesc::MakeInvalid();
357 // This type only describes color channels.
358 case MTLPixelFormatStencil8: return GrColorFormatDesc::MakeInvalid();
361 return GrColorFormatDesc::MakeInvalid();
365 SkImage::CompressionType GrMtlBackendFormatToCompressionType(const GrBackendFormat& format) {
366 MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
367 return GrMtlFormatToCompressionType(mtlFormat);
370 bool GrMtlFormatIsCompressed(MTLPixelFormat mtlFormat) {
372 #ifdef SK_BUILD_FOR_IOS
373 case MTLPixelFormatETC2_RGB8:
376 case MTLPixelFormatBC1_RGBA:
384 SkImage::CompressionType GrMtlFormatToCompressionType(MTLPixelFormat mtlFormat) {
386 #ifdef SK_BUILD_FOR_IOS
387 case MTLPixelFormatETC2_RGB8: return SkImage::CompressionType::kETC2_RGB8_UNORM;
389 case MTLPixelFormatBC1_RGBA: return SkImage::CompressionType::kBC1_RGBA8_UNORM;
391 default: return SkImage::CompressionType::kNone;
397 int GrMtlTextureInfoSampleCount(const GrMtlTextureInfo& info) {
398 id<MTLTexture> texture = GrGetMTLTexture(info.fTexture.get());
402 return texture.sampleCount;
405 size_t GrMtlBackendFormatBytesPerBlock(const GrBackendFormat& format) {
406 MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
407 return GrMtlFormatBytesPerBlock(mtlFormat);
410 size_t GrMtlFormatBytesPerBlock(MTLPixelFormat 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;
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;
427 #ifdef SK_BUILD_FOR_IOS
428 case MTLPixelFormatABGR4Unorm: return 2;
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;
436 case MTLPixelFormatBC1_RGBA: return 8;
438 case MTLPixelFormatRGBA16Unorm: return 8;
439 case MTLPixelFormatRG16Float: return 4;
440 case MTLPixelFormatStencil8: return 1;
446 int GrMtlBackendFormatStencilBits(const GrBackendFormat& format) {
447 MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
448 return GrMtlFormatStencilBits(mtlFormat);
451 int GrMtlFormatStencilBits(MTLPixelFormat mtlFormat) {
453 case MTLPixelFormatStencil8:
460 #ifdef SK_BUILD_FOR_IOS
461 bool GrMtlIsAppInBackground() {
462 return [NSThread isMainThread] &&
463 ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground);
467 #if defined(SK_DEBUG) || GR_TEST_UTILS
468 bool GrMtlFormatIsBGRA8(GrMTLPixelFormat mtlFormat) {
469 return mtlFormat == MTLPixelFormatBGRA8Unorm;
472 const char* GrMtlFormatToStr(GrMTLPixelFormat 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";
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";
489 #ifdef SK_BUILD_FOR_IOS
490 case MTLPixelFormatABGR4Unorm: return "ABGR4Unorm";
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";
498 case MTLPixelFormatBC1_RGBA: return "BC1_RGBA";
500 case MTLPixelFormatRGBA16Unorm: return "RGBA16Unorm";
501 case MTLPixelFormatRG16Float: return "RG16Float";
502 case MTLPixelFormatStencil8: return "Stencil8";
504 default: return "Unknown";