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/GrSurface.h" 11#include "include/private/GrTypesPriv.h" 12#include "src/gpu/mtl/GrMtlGpu.h" 13#include "src/gpu/mtl/GrMtlRenderTarget.h" 14#include "src/gpu/mtl/GrMtlTexture.h" 15#include "src/sksl/SkSLCompiler.h" 16 17#import <Metal/Metal.h> 18 19#if !__has_feature(objc_arc) 20#error This file must be compiled with Arc. Use -fobjc-arc flag 21#endif 22 23#define PRINT_MSL 0 // print out the MSL code generated 24 25bool GrPixelConfigToMTLFormat(GrPixelConfig config, MTLPixelFormat* format) { 26 MTLPixelFormat dontCare; 27 if (!format) { 28 format = &dontCare; 29 } 30 31 switch (config) { 32 case kUnknown_GrPixelConfig: 33 return false; 34 case kRGBA_8888_GrPixelConfig: 35 *format = MTLPixelFormatRGBA8Unorm; 36 return true; 37 case kRGB_888_GrPixelConfig: 38 *format = MTLPixelFormatRGBA8Unorm; 39 return true; 40 case kRGB_888X_GrPixelConfig: 41 *format = MTLPixelFormatRGBA8Unorm; 42 return true; 43 case kRG_88_GrPixelConfig: 44 *format = MTLPixelFormatRG8Unorm; 45 return true; 46 case kBGRA_8888_GrPixelConfig: 47 *format = MTLPixelFormatBGRA8Unorm; 48 return true; 49 case kSRGBA_8888_GrPixelConfig: 50 *format = MTLPixelFormatRGBA8Unorm_sRGB; 51 return true; 52 case kRGBA_1010102_GrPixelConfig: 53 *format = MTLPixelFormatRGB10A2Unorm; 54 return true; 55 case kRGB_565_GrPixelConfig: 56#ifdef SK_BUILD_FOR_IOS 57 *format = MTLPixelFormatB5G6R5Unorm; 58 return true; 59#else 60 return false; 61#endif 62 case kRGBA_4444_GrPixelConfig: 63#ifdef SK_BUILD_FOR_IOS 64 *format = MTLPixelFormatABGR4Unorm; 65 return true; 66#else 67 return false; 68#endif 69 case kAlpha_8_GrPixelConfig: // fall through 70 case kAlpha_8_as_Red_GrPixelConfig: 71 *format = MTLPixelFormatR8Unorm; 72 return true; 73 case kAlpha_8_as_Alpha_GrPixelConfig: 74 *format = MTLPixelFormatA8Unorm; 75 return true; 76 case kGray_8_GrPixelConfig: // fall through 77 case kGray_8_as_Red_GrPixelConfig: 78 *format = MTLPixelFormatR8Unorm; 79 return true; 80 case kGray_8_as_Lum_GrPixelConfig: 81 return false; 82 case kRGBA_half_GrPixelConfig: 83 *format = MTLPixelFormatRGBA16Float; 84 return true; 85 case kRGBA_half_Clamped_GrPixelConfig: 86 *format = MTLPixelFormatRGBA16Float; 87 return true; 88 case kAlpha_half_GrPixelConfig: // fall through 89 case kAlpha_half_as_Red_GrPixelConfig: 90 *format = MTLPixelFormatR16Float; 91 return true; 92 case kAlpha_half_as_Lum_GrPixelConfig: 93 return false; 94 case kRGB_ETC1_GrPixelConfig: 95#ifdef SK_BUILD_FOR_IOS 96 *format = MTLPixelFormatETC2_RGB8; 97 return true; 98#else 99 return false; 100#endif 101 case kAlpha_16_GrPixelConfig: 102 *format = MTLPixelFormatR16Unorm; 103 return true; 104 case kRG_1616_GrPixelConfig: 105 *format = MTLPixelFormatRG16Unorm; 106 return true; 107 case kRGBA_16161616_GrPixelConfig: 108 *format = MTLPixelFormatRGBA16Unorm; 109 return true; 110 case kRG_half_GrPixelConfig: 111 *format = MTLPixelFormatRG16Float; 112 return true; 113 } 114 SK_ABORT("Unexpected config"); 115} 116 117MTLTextureDescriptor* GrGetMTLTextureDescriptor(id<MTLTexture> mtlTexture) { 118 MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init]; 119 texDesc.textureType = mtlTexture.textureType; 120 texDesc.pixelFormat = mtlTexture.pixelFormat; 121 texDesc.width = mtlTexture.width; 122 texDesc.height = mtlTexture.height; 123 texDesc.depth = mtlTexture.depth; 124 texDesc.mipmapLevelCount = mtlTexture.mipmapLevelCount; 125 texDesc.arrayLength = mtlTexture.arrayLength; 126 texDesc.sampleCount = mtlTexture.sampleCount; 127 if (@available(macOS 10.11, iOS 9.0, *)) { 128 texDesc.usage = mtlTexture.usage; 129 } 130 return texDesc; 131} 132 133#if PRINT_MSL 134void print_msl(const char* source) { 135 SkTArray<SkString> lines; 136 SkStrSplit(source, "\n", kStrict_SkStrSplitMode, &lines); 137 for (int i = 0; i < lines.count(); i++) { 138 SkString& line = lines[i]; 139 line.prependf("%4i\t", i + 1); 140 SkDebugf("%s\n", line.c_str()); 141 } 142} 143#endif 144 145id<MTLLibrary> GrCompileMtlShaderLibrary(const GrMtlGpu* gpu, 146 const char* shaderString, 147 SkSL::Program::Kind kind, 148 const SkSL::Program::Settings& settings, 149 SkSL::Program::Inputs* outInputs) { 150 std::unique_ptr<SkSL::Program> program = 151 gpu->shaderCompiler()->convertProgram(kind, 152 SkSL::String(shaderString), 153 settings); 154 155 if (!program) { 156 SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str()); 157 SkASSERT(false); 158 return nil; 159 } 160 161 *outInputs = program->fInputs; 162 SkSL::String code; 163 if (!gpu->shaderCompiler()->toMetal(*program, &code)) { 164 SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str()); 165 SkASSERT(false); 166 return nil; 167 } 168 NSString* mtlCode = [[NSString alloc] initWithCString: code.c_str() 169 encoding: NSASCIIStringEncoding]; 170#if PRINT_MSL 171 print_msl([mtlCode cStringUsingEncoding: NSASCIIStringEncoding]); 172#endif 173 174 MTLCompileOptions* defaultOptions = [[MTLCompileOptions alloc] init]; 175#if defined(SK_BUILD_FOR_MAC) && defined(GR_USE_COMPLETION_HANDLER) 176 bool timedout; 177 id<MTLLibrary> compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), mtlCode, 178 defaultOptions, &timedout); 179 if (timedout) { 180 // try again 181 compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), mtlCode, 182 defaultOptions, &timedout); 183 } 184#else 185 NSError* error = nil; 186 id<MTLLibrary> compiledLibrary = [gpu->device() newLibraryWithSource: mtlCode 187 options: defaultOptions 188 error: &error]; 189 if (error) { 190 SkDebugf("Error compiling MSL shader: %s\n%s\n", 191 code.c_str(), 192 [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]); 193 return nil; 194 } 195#endif 196 return compiledLibrary; 197} 198 199id<MTLLibrary> GrMtlNewLibraryWithSource(id<MTLDevice> device, NSString* mslCode, 200 MTLCompileOptions* options, bool* timedout) { 201 dispatch_semaphore_t compilerSemaphore = dispatch_semaphore_create(0); 202 203 __block dispatch_semaphore_t semaphore = compilerSemaphore; 204 __block id<MTLLibrary> compiledLibrary; 205 [device newLibraryWithSource: mslCode 206 options: options 207 completionHandler: 208 ^(id<MTLLibrary> library, NSError* error) { 209 if (error) { 210 SkDebugf("Error compiling MSL shader: %s\n%s\n", 211 mslCode, 212 [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]); 213 } 214 compiledLibrary = library; 215 dispatch_semaphore_signal(semaphore); 216 } 217 ]; 218 219 // Wait 100 ms for the compiler 220 if (dispatch_semaphore_wait(compilerSemaphore, dispatch_time(DISPATCH_TIME_NOW, 100000))) { 221 SkDebugf("Timeout compiling MSL shader\n"); 222 *timedout = true; 223 return nil; 224 } 225 226 *timedout = false; 227 return compiledLibrary; 228} 229 230id<MTLRenderPipelineState> GrMtlNewRenderPipelineStateWithDescriptor( 231 id<MTLDevice> device, MTLRenderPipelineDescriptor* pipelineDescriptor, bool* timedout) { 232 dispatch_semaphore_t pipelineSemaphore = dispatch_semaphore_create(0); 233 234 __block dispatch_semaphore_t semaphore = pipelineSemaphore; 235 __block id<MTLRenderPipelineState> pipelineState; 236 [device newRenderPipelineStateWithDescriptor: pipelineDescriptor 237 completionHandler: 238 ^(id<MTLRenderPipelineState> state, NSError* error) { 239 if (error) { 240 SkDebugf("Error creating pipeline: %s\n", 241 [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]); 242 } 243 pipelineState = state; 244 dispatch_semaphore_signal(semaphore); 245 } 246 ]; 247 248 // Wait 500 ms for pipeline creation 249 if (dispatch_semaphore_wait(pipelineSemaphore, dispatch_time(DISPATCH_TIME_NOW, 500000))) { 250 SkDebugf("Timeout creating pipeline.\n"); 251 *timedout = true; 252 return nil; 253 } 254 255 *timedout = false; 256 return pipelineState; 257} 258 259id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface) { 260 id<MTLTexture> mtlTexture = nil; 261 262 GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget()); 263 GrMtlTexture* texture; 264 if (renderTarget) { 265 // We should not be using this for multisampled rendertargets 266 if (renderTarget->numSamples() > 1) { 267 SkASSERT(false); 268 return nil; 269 } 270 mtlTexture = renderTarget->mtlColorTexture(); 271 } else { 272 texture = static_cast<GrMtlTexture*>(surface->asTexture()); 273 if (texture) { 274 mtlTexture = texture->mtlTexture(); 275 } 276 } 277 return mtlTexture; 278} 279 280 281////////////////////////////////////////////////////////////////////////////// 282// CPP Utils 283 284GrMTLPixelFormat GrGetMTLPixelFormatFromMtlTextureInfo(const GrMtlTextureInfo& info) { 285 id<MTLTexture> mtlTexture = GrGetMTLTexture(info.fTexture.get()); 286 return static_cast<GrMTLPixelFormat>(mtlTexture.pixelFormat); 287} 288 289bool GrMtlFormatIsCompressed(MTLPixelFormat mtlFormat) { 290 switch (mtlFormat) { 291#ifdef SK_BUILD_FOR_IOS 292 case MTLPixelFormatETC2_RGB8: 293 return true; 294#endif 295 default: 296 return false; 297 } 298} 299 300bool GrMtlFormatToCompressionType(MTLPixelFormat mtlFormat, 301 SkImage::CompressionType* compressionType) { 302 switch (mtlFormat) { 303#ifdef SK_BUILD_FOR_IOS 304 case MTLPixelFormatETC2_RGB8: 305 *compressionType = SkImage::kETC1_CompressionType; 306 return true; 307#endif 308 default: 309 return false; 310 } 311} 312 313#if GR_TEST_UTILS 314bool GrMtlFormatIsBGRA(GrMTLPixelFormat mtlFormat) { 315 return mtlFormat == MTLPixelFormatBGRA8Unorm; 316} 317 318const char* GrMtlFormatToStr(GrMTLPixelFormat mtlFormat) { 319 switch (mtlFormat) { 320 case MTLPixelFormatInvalid: return "Invalid"; 321 case MTLPixelFormatRGBA8Unorm: return "RGBA8Unorm"; 322 case MTLPixelFormatR8Unorm: return "R8Unorm"; 323 case MTLPixelFormatA8Unorm: return "A8Unorm"; 324 case MTLPixelFormatBGRA8Unorm: return "BGRA8Unorm"; 325#ifdef SK_BUILD_FOR_IOS 326 case MTLPixelFormatB5G6R5Unorm: return "B5G6R5Unorm"; 327#endif 328 case MTLPixelFormatRGBA16Float: return "RGBA16Float"; 329 case MTLPixelFormatR16Float: return "R16Float"; 330 case MTLPixelFormatRG8Unorm: return "RG8Unorm"; 331 case MTLPixelFormatRGB10A2Unorm: return "RGB10A2Unorm"; 332#ifdef SK_BUILD_FOR_IOS 333 case MTLPixelFormatABGR4Unorm: return "ABGR4Unorm"; 334#endif 335 case MTLPixelFormatRGBA8Unorm_sRGB: return "RGBA8Unorm_sRGB"; 336 case MTLPixelFormatR16Unorm: return "R16Unorm"; 337 case MTLPixelFormatRG16Unorm: return "RG16Unorm"; 338#ifdef SK_BUILD_FOR_IOS 339 case MTLPixelFormatETC2_RGB8: return "ETC2_RGB8"; 340#endif 341 case MTLPixelFormatRGBA16Unorm: return "RGBA16Unorm"; 342 case MTLPixelFormatRG16Float: return "RG16Float"; 343 344 default: return "Unknown"; 345 } 346} 347 348#endif 349 350 351 352