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#ifdef SK_BUILD_FOR_IOS 23#import <UIKit/UIApplication.h> 24#endif 25 26#if !__has_feature(objc_arc) 27#error This file must be compiled with Arc. Use -fobjc-arc flag 28#endif 29 30GR_NORETAIN_BEGIN 31 32NSError* 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 37 userInfo:userInfo]; 38} 39 40MTLTextureDescriptor* 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; 52 } 53 return texDesc; 54} 55 56// Print the source code for all shaders generated. 57static const bool gPrintSKSL = false; 58static const bool gPrintMSL = false; 59 60bool GrSkSLToMSL(const GrMtlGpu* gpu, 61 const SkSL::String& sksl, 62 SkSL::ProgramKind programKind, 63 const SkSL::Program::Settings& settings, 64 SkSL::String* msl, 65 SkSL::Program::Inputs* outInputs, 66 GrContextOptions::ShaderErrorHandler* errorHandler) { 67#ifdef SK_DEBUG 68 SkSL::String src = GrShaderUtils::PrettyPrint(sksl); 69#else 70 const SkSL::String& src = sksl; 71#endif 72 SkSL::Compiler* compiler = gpu->shaderCompiler(); 73 std::unique_ptr<SkSL::Program> program = 74 gpu->shaderCompiler()->convertProgram(programKind, 75 src, 76 settings); 77 if (!program || !compiler->toMetal(*program, msl)) { 78 errorHandler->compileError(src.c_str(), compiler->errorText().c_str()); 79 return false; 80 } 81 82 if (gPrintSKSL || gPrintMSL) { 83 GrShaderUtils::PrintShaderBanner(programKind); 84 if (gPrintSKSL) { 85 SkDebugf("SKSL:\n"); 86 GrShaderUtils::PrintLineByLine(GrShaderUtils::PrettyPrint(sksl)); 87 } 88 if (gPrintMSL) { 89 SkDebugf("MSL:\n"); 90 GrShaderUtils::PrintLineByLine(GrShaderUtils::PrettyPrint(*msl)); 91 } 92 } 93 94 *outInputs = program->fInputs; 95 return true; 96} 97 98id<MTLLibrary> GrCompileMtlShaderLibrary(const GrMtlGpu* gpu, 99 const SkSL::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()) 103 length:msl.size() 104 encoding:NSUTF8StringEncoding 105 freeWhenDone:NO]; 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; 114#endif 115 } 116 if (gpu->caps()->shaderCaps()->canUseFastMath()) { 117 options.fastMathEnabled = YES; 118 } 119 120 NSError* error = nil; 121#if defined(SK_BUILD_FOR_MAC) 122 id<MTLLibrary> compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), nsSource, 123 options, &error); 124#else 125 id<MTLLibrary> compiledLibrary = [gpu->device() newLibraryWithSource:nsSource 126 options:options 127 error:&error]; 128#endif 129 if (!compiledLibrary) { 130 errorHandler->compileError(msl.c_str(), error.debugDescription.UTF8String); 131 return nil; 132 } 133 134 return compiledLibrary; 135} 136 137void GrPrecompileMtlShaderLibrary(const GrMtlGpu* gpu, 138 const SkSL::String& msl) { 139 auto nsSource = [[NSString alloc] initWithBytesNoCopy:const_cast<char*>(msl.c_str()) 140 length:msl.size() 141 encoding:NSUTF8StringEncoding 142 freeWhenDone:NO]; 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 148 options:nil 149 completionHandler:completionHandler]; 150} 151 152// Wrapper to get atomic assignment for compiles and pipeline creation 153class MtlCompileResult : public SkRefCnt { 154public: 155 MtlCompileResult() : fCompiledObject(nil), fError(nil) {} 156 void set(id compiledObject, NSError* error) { 157 SkAutoMutexExclusive automutex(fMutex); 158 fCompiledObject = compiledObject; 159 fError = error; 160 } 161 std::pair<id, NSError*> get() { 162 SkAutoMutexExclusive automutex(fMutex); 163 return std::make_pair(fCompiledObject, fError); 164 } 165private: 166 SkMutex fMutex; 167 id fCompiledObject SK_GUARDED_BY(fMutex); 168 NSError* fError SK_GUARDED_BY(fMutex); 169}; 170 171id<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(); 182 }; 183 184 [device newLibraryWithSource: mslCode 185 options: options 186 completionHandler: completionHandler]; 187 188 // Wait 1 second for the compiler 189 constexpr auto kTimeoutNS = 1000000000UL; 190 if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) { 191 if (error) { 192 constexpr auto kTimeoutMS = kTimeoutNS/1000000UL; 193 NSString* description = 194 [NSString stringWithFormat:@"Compilation took longer than %lu ms", 195 kTimeoutMS]; 196 *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout); 197 } 198 return nil; 199 } 200 201 id<MTLLibrary> compiledLibrary; 202 std::tie(compiledLibrary, *error) = compileResult->get(); 203 204 return compiledLibrary; 205} 206 207id<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(); 218 }; 219 220 [device newRenderPipelineStateWithDescriptor: pipelineDescriptor 221 completionHandler: completionHandler]; 222 223 // Wait 1 second for pipeline creation 224 constexpr auto kTimeoutNS = 1000000000UL; 225 if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) { 226 if (error) { 227 constexpr auto kTimeoutMS = kTimeoutNS/1000000UL; 228 NSString* description = 229 [NSString stringWithFormat:@"Pipeline creation took longer than %lu ms", 230 kTimeoutMS]; 231 *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout); 232 } 233 return nil; 234 } 235 236 id<MTLRenderPipelineState> pipelineState; 237 std::tie(pipelineState, *error) = compileResult->get(); 238 239 return pipelineState; 240} 241 242id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface) { 243 id<MTLTexture> mtlTexture = nil; 244 245 GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget()); 246 GrMtlTexture* texture; 247 if (renderTarget) { 248 // We should not be using this for multisampled rendertargets with a separate resolve 249 // texture. 250 if (renderTarget->resolveAttachment()) { 251 SkASSERT(renderTarget->numSamples() > 1); 252 SkASSERT(false); 253 return nil; 254 } 255 mtlTexture = renderTarget->colorMTLTexture(); 256 } else { 257 texture = static_cast<GrMtlTexture*>(surface->asTexture()); 258 if (texture) { 259 mtlTexture = texture->mtlTexture(); 260 } 261 } 262 return mtlTexture; 263} 264 265 266////////////////////////////////////////////////////////////////////////////// 267// CPP Utils 268 269GrMTLPixelFormat GrGetMTLPixelFormatFromMtlTextureInfo(const GrMtlTextureInfo& info) { 270 id<MTLTexture> GR_NORETAIN mtlTexture = GrGetMTLTexture(info.fTexture.get()); 271 return static_cast<GrMTLPixelFormat>(mtlTexture.pixelFormat); 272} 273 274uint32_t GrMtlFormatChannels(GrMTLPixelFormat mtlFormat) { 275 switch (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; 282#endif 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; 289#endif 290#if defined(SK_BUILD_FOR_IOS) && !TARGET_OS_SIMULATOR 291 case MTLPixelFormatABGR4Unorm: return kRGBA_SkColorChannelFlags; 292#endif 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; 298#else 299 case MTLPixelFormatBC1_RGBA: return kRGBA_SkColorChannelFlags; 300#endif 301 case MTLPixelFormatRGBA16Unorm: return kRGBA_SkColorChannelFlags; 302 case MTLPixelFormatRG16Float: return kRG_SkColorChannelFlags; 303 case MTLPixelFormatStencil8: return 0; 304 305 default: return 0; 306 } 307} 308 309GrColorFormatDesc GrMtlFormatDesc(GrMTLPixelFormat mtlFormat) { 310 switch (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); 322#endif 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); 334#endif 335#if defined(SK_BUILD_FOR_IOS) && !TARGET_OS_SIMULATOR 336 case MTLPixelFormatABGR4Unorm: 337 return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm); 338#endif 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); 349 350 // Compressed texture formats are not expected to have a description. 351#ifdef SK_BUILD_FOR_IOS 352 case MTLPixelFormatETC2_RGB8: return GrColorFormatDesc::MakeInvalid(); 353#else 354 case MTLPixelFormatBC1_RGBA: return GrColorFormatDesc::MakeInvalid(); 355#endif 356 357 // This type only describes color channels. 358 case MTLPixelFormatStencil8: return GrColorFormatDesc::MakeInvalid(); 359 360 default: 361 return GrColorFormatDesc::MakeInvalid(); 362 } 363} 364 365SkImage::CompressionType GrMtlBackendFormatToCompressionType(const GrBackendFormat& format) { 366 MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format); 367 return GrMtlFormatToCompressionType(mtlFormat); 368} 369 370bool GrMtlFormatIsCompressed(MTLPixelFormat mtlFormat) { 371 switch (mtlFormat) { 372#ifdef SK_BUILD_FOR_IOS 373 case MTLPixelFormatETC2_RGB8: 374 return true; 375#else 376 case MTLPixelFormatBC1_RGBA: 377 return true; 378#endif 379 default: 380 return false; 381 } 382} 383 384SkImage::CompressionType GrMtlFormatToCompressionType(MTLPixelFormat mtlFormat) { 385 switch (mtlFormat) { 386#ifdef SK_BUILD_FOR_IOS 387 case MTLPixelFormatETC2_RGB8: return SkImage::CompressionType::kETC2_RGB8_UNORM; 388#else 389 case MTLPixelFormatBC1_RGBA: return SkImage::CompressionType::kBC1_RGBA8_UNORM; 390#endif 391 default: return SkImage::CompressionType::kNone; 392 } 393 394 SkUNREACHABLE; 395} 396 397int GrMtlTextureInfoSampleCount(const GrMtlTextureInfo& info) { 398 id<MTLTexture> texture = GrGetMTLTexture(info.fTexture.get()); 399 if (!texture) { 400 return 0; 401 } 402 return texture.sampleCount; 403} 404 405size_t GrMtlBackendFormatBytesPerBlock(const GrBackendFormat& format) { 406 MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format); 407 return GrMtlFormatBytesPerBlock(mtlFormat); 408} 409 410size_t GrMtlFormatBytesPerBlock(MTLPixelFormat mtlFormat) { 411 switch (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; 419#endif 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; 426#endif 427#ifdef SK_BUILD_FOR_IOS 428 case MTLPixelFormatABGR4Unorm: return 2; 429#endif 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; 435#else 436 case MTLPixelFormatBC1_RGBA: return 8; 437#endif 438 case MTLPixelFormatRGBA16Unorm: return 8; 439 case MTLPixelFormatRG16Float: return 4; 440 case MTLPixelFormatStencil8: return 1; 441 442 default: return 0; 443 } 444} 445 446int GrMtlBackendFormatStencilBits(const GrBackendFormat& format) { 447 MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format); 448 return GrMtlFormatStencilBits(mtlFormat); 449} 450 451int GrMtlFormatStencilBits(MTLPixelFormat mtlFormat) { 452 switch(mtlFormat) { 453 case MTLPixelFormatStencil8: 454 return 8; 455 default: 456 return 0; 457 } 458} 459 460#ifdef SK_BUILD_FOR_IOS 461bool GrMtlIsAppInBackground() { 462 return [NSThread isMainThread] && 463 ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground); 464} 465#endif 466 467#if defined(SK_DEBUG) || GR_TEST_UTILS 468bool GrMtlFormatIsBGRA8(GrMTLPixelFormat mtlFormat) { 469 return mtlFormat == MTLPixelFormatBGRA8Unorm; 470} 471 472const char* GrMtlFormatToStr(GrMTLPixelFormat mtlFormat) { 473 switch (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"; 481#endif 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"; 488#endif 489#ifdef SK_BUILD_FOR_IOS 490 case MTLPixelFormatABGR4Unorm: return "ABGR4Unorm"; 491#endif 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"; 497#else 498 case MTLPixelFormatBC1_RGBA: return "BC1_RGBA"; 499#endif 500 case MTLPixelFormatRGBA16Unorm: return "RGBA16Unorm"; 501 case MTLPixelFormatRG16Float: return "RG16Float"; 502 case MTLPixelFormatStencil8: return "Stencil8"; 503 504 default: return "Unknown"; 505 } 506} 507 508#endif 509 510GR_NORETAIN_END 511