Use asynchronous routines to build Metal shaders and pipelines for MacOS.
On Mac, Metal will trigger an xpc to a process to compile shaders and
link pipeline programs. Sometimes that process can crash or hang. By using
an asynchronous call with a timeout we can at least recover in this case.
Bug: chromium:974219
Change-Id: I179daa86979b1217458e7be210fccd5edcbffdd0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/222884
Reviewed-by: Christopher Cameron <ccameron@chromium.org>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/mtl/GrMtlUtil.mm b/src/gpu/mtl/GrMtlUtil.mm
index 007abe2..7caf2f5 100644
--- a/src/gpu/mtl/GrMtlUtil.mm
+++ b/src/gpu/mtl/GrMtlUtil.mm
@@ -178,6 +178,16 @@
#endif
MTLCompileOptions* defaultOptions = [[MTLCompileOptions alloc] init];
+#ifdef SK_BUILD_FOR_MAC
+ bool timedout;
+ id<MTLLibrary> compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), mtlCode,
+ defaultOptions, &timedout);
+ if (timedout) {
+ // try again
+ compiledLibrary = GrMtlNewLibraryWithSource(gpu->device(), mtlCode,
+ defaultOptions, &timedout);
+ }
+#else
NSError* error = nil;
id<MTLLibrary> compiledLibrary = [gpu->device() newLibraryWithSource: mtlCode
options: defaultOptions
@@ -187,9 +197,69 @@
[[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
return nil;
}
+#endif
return compiledLibrary;
}
+id<MTLLibrary> GrMtlNewLibraryWithSource(id<MTLDevice> device, NSString* mslCode,
+ MTLCompileOptions* options, bool* timedout) {
+ dispatch_semaphore_t compilerSemaphore = dispatch_semaphore_create(0);
+
+ __block dispatch_semaphore_t semaphore = compilerSemaphore;
+ __block id<MTLLibrary> compiledLibrary;
+ [device newLibraryWithSource: mslCode
+ options: options
+ completionHandler:
+ ^(id<MTLLibrary> library, NSError* error) {
+ if (error) {
+ SkDebugf("Error compiling MSL shader: %s\n",
+ [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
+ }
+ compiledLibrary = library;
+ dispatch_semaphore_signal(semaphore);
+ }
+ ];
+
+ // Wait 100 ms for the compiler
+ if (dispatch_semaphore_wait(compilerSemaphore, dispatch_time(DISPATCH_TIME_NOW, 100000))) {
+ SkDebugf("Timeout compiling MSL shader\n");
+ *timedout = true;
+ return nil;
+ }
+
+ *timedout = false;
+ return compiledLibrary;
+}
+
+id<MTLRenderPipelineState> GrMtlNewRenderPipelineStateWithDescriptor(
+ id<MTLDevice> device, MTLRenderPipelineDescriptor* pipelineDescriptor, bool* timedout) {
+ dispatch_semaphore_t pipelineSemaphore = dispatch_semaphore_create(0);
+
+ __block dispatch_semaphore_t semaphore = pipelineSemaphore;
+ __block id<MTLRenderPipelineState> pipelineState;
+ [device newRenderPipelineStateWithDescriptor: pipelineDescriptor
+ completionHandler:
+ ^(id<MTLRenderPipelineState> state, NSError* error) {
+ if (error) {
+ SkDebugf("Error creating pipeline: %s\n",
+ [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
+ }
+ pipelineState = state;
+ dispatch_semaphore_signal(semaphore);
+ }
+ ];
+
+ // Wait 500 ms for pipeline creation
+ if (dispatch_semaphore_wait(pipelineSemaphore, dispatch_time(DISPATCH_TIME_NOW, 500000))) {
+ SkDebugf("Timeout creating pipeline.\n");
+ *timedout = true;
+ return nil;
+ }
+
+ *timedout = false;
+ return pipelineState;
+}
+
id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface, bool doResolve) {
id<MTLTexture> mtlTexture = nil;