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