Set NSError on compilation/link timeouts.

When compilation fails GrCompileMtlShaderLibrary expects the error
result to be set. This also allows us to print out all errors with
compilation and pipeline creation in central locations.

Change-Id: I7c3d5dda5bd46a95b55365cb0b8f07d79c030db6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/268625
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/mtl/GrMtlUtil.h b/src/gpu/mtl/GrMtlUtil.h
index 1031d40..6df99c7 100644
--- a/src/gpu/mtl/GrMtlUtil.h
+++ b/src/gpu/mtl/GrMtlUtil.h
@@ -53,6 +53,11 @@
     return (__bridge_retained const void*)idObject;
 }
 
+enum class GrMtlErrorCode {
+    kTimeout = 1,
+};
+
+NSError* GrCreateMtlError(NSString* description, GrMtlErrorCode errorCode);
 
 /**
  * Returns a MTLTextureDescriptor which describes the MTLTexture. Useful when creating a duplicate
diff --git a/src/gpu/mtl/GrMtlUtil.mm b/src/gpu/mtl/GrMtlUtil.mm
index 0770af6..b681be3 100644
--- a/src/gpu/mtl/GrMtlUtil.mm
+++ b/src/gpu/mtl/GrMtlUtil.mm
@@ -23,6 +23,14 @@
 
 #define PRINT_MSL 0 // print out the MSL code generated
 
+NSError* GrCreateMtlError(NSString* description, GrMtlErrorCode errorCode) {
+    NSDictionary* userInfo = [NSDictionary dictionaryWithObject:description
+                                                         forKey:NSLocalizedDescriptionKey];
+    return [NSError errorWithDomain:@"org.skia.ganesh"
+                               code:(NSInteger)errorCode
+                           userInfo:userInfo];
+}
+
 MTLTextureDescriptor* GrGetMTLTextureDescriptor(id<MTLTexture> mtlTexture) {
     MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
     texDesc.textureType = mtlTexture.textureType;
@@ -144,8 +152,15 @@
                completionHandler: completionHandler];
 
     // Wait 100 ms for the compiler
-    if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 100000000UL))) {
-        SkDebugf("Timeout compiling MSL shader\n");
+    constexpr auto kTimeoutNS = 100000000UL;
+    if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) {
+        if (error) {
+            constexpr auto kTimeoutMS = kTimeoutNS/1000000UL;
+            NSString* description =
+                    [NSString stringWithFormat:@"Compilation took longer than %lu ms",
+                                               kTimeoutMS];
+            *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout);
+        }
         return nil;
     }
 
@@ -172,8 +187,15 @@
                                completionHandler: completionHandler];
 
     // Wait 100 ms for pipeline creation
-    if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 100000000UL))) {
-        SkDebugf("Timeout creating pipeline.\n");
+    constexpr auto kTimeoutNS = 100000000UL;
+    if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutNS))) {
+        if (error) {
+            constexpr auto kTimeoutMS = kTimeoutNS/1000000UL;
+            NSString* description =
+                    [NSString stringWithFormat:@"Pipeline creation took longer than %lu ms",
+                                               kTimeoutMS];
+            *error = GrCreateMtlError(description, GrMtlErrorCode::kTimeout);
+        }
         return nil;
     }