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