Add MoltenVK support to Viewer.

Works with v1.0.17, will probably need updating for later revisions.

Bug: skia:8737
Change-Id: I9e42fad90656a88efa12625856019a8282ff39fd
Reviewed-on: https://skia-review.googlesource.com/c/191298
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index b194f2f..4dcfeb1 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2168,6 +2168,9 @@
         libs += [ "X11-xcb" ]
       } else if (is_win) {
         sources += [ "tools/sk_app/win/VulkanWindowContext_win.cpp" ]
+      } else if (is_mac) {
+        sources += [ "tools/sk_app/mac/VulkanWindowContext_mac.mm" ]
+        libs += [ "MetalKit.framework" ]
       }
     }
 
diff --git a/tools/sk_app/mac/VulkanWindowContext_mac.mm b/tools/sk_app/mac/VulkanWindowContext_mac.mm
new file mode 100644
index 0000000..eece8b9
--- /dev/null
+++ b/tools/sk_app/mac/VulkanWindowContext_mac.mm
@@ -0,0 +1,142 @@
+
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "vk/GrVkVulkan.h"
+
+#include "vk/GrVkInterface.h"
+#include "vk/GrVkUtil.h"
+
+#include "vk/VkTestUtils.h"
+
+#include "WindowContextFactory_mac.h"
+#include "../VulkanWindowContext.h"
+#include "vulkan/vulkan_macos.h"
+
+#import <MetalKit/MetalKit.h>
+
+namespace sk_app {
+
+class VulkanWindowContext_mac : public VulkanWindowContext {
+public:
+    VulkanWindowContext_mac(MTKView* mtkView,
+                            const DisplayParams& params,
+                            CreateVkSurfaceFn createVkSurface,
+                            CanPresentFn canPresent,
+                            PFN_vkGetInstanceProcAddr instProc,
+                            PFN_vkGetDeviceProcAddr devProc);
+
+    ~VulkanWindowContext_mac() override;
+
+private:
+    MTKView*              fMTKView;
+
+    typedef VulkanWindowContext INHERITED;
+};
+
+VulkanWindowContext_mac::VulkanWindowContext_mac(MTKView* mtkView,
+                                                 const DisplayParams& params,
+                                                 CreateVkSurfaceFn createVkSurface,
+                                                 CanPresentFn canPresent,
+                                                 PFN_vkGetInstanceProcAddr instProc,
+                                                 PFN_vkGetDeviceProcAddr devProc)
+    : INHERITED(params, createVkSurface, canPresent, instProc, devProc)
+    , fMTKView(mtkView) {
+
+    // any config code here (particularly for msaa)?
+}
+
+VulkanWindowContext_mac::~VulkanWindowContext_mac() {
+    [fMTKView removeFromSuperview];
+    [fMTKView release];
+    fMTKView = nil;
+}
+
+namespace window_context_factory {
+
+WindowContext* NewVulkanForMac(const MacWindowInfo& info, const DisplayParams& displayParams) {
+    PFN_vkGetInstanceProcAddr instProc;
+    PFN_vkGetDeviceProcAddr devProc;
+    if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
+        return nullptr;
+    }
+
+    // Create mtkview
+    NSRect rect = info.fMainView.frame;
+    MTKView* mtkView = [[MTKView alloc] initWithFrame:rect device:nil];
+    if (nil == mtkView) {
+        return nullptr;
+    }
+
+    mtkView.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
+
+//    if (fDisplayParams.fMSAASampleCount > 1) {
+//        if (![fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) {
+//            return nullptr;
+//        }
+//    }
+//    mtkView.sampleCount = fDisplayParams.fMSAASampleCount;
+
+    // attach Metal view to main view
+    [mtkView setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    [info.fMainView addSubview:mtkView];
+    NSDictionary *views = NSDictionaryOfVariableBindings(mtkView);
+
+    [info.fMainView addConstraints:
+     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mtkView]|"
+                                             options:0
+                                             metrics:nil
+                                               views:views]];
+
+    [info.fMainView addConstraints:
+     [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mtkView]|"
+                                             options:0
+                                             metrics:nil
+                                               views:views]];
+
+    auto createVkSurface = [mtkView, instProc](VkInstance instance) -> VkSurfaceKHR {
+        static PFN_vkCreateMacOSSurfaceMVK createMacOSSurfaceMVK = nullptr;
+        if (!createMacOSSurfaceMVK) {
+            createMacOSSurfaceMVK =
+                    (PFN_vkCreateMacOSSurfaceMVK) instProc(instance, "vkCreateMacOSSurfaceMVK");
+        }
+
+        VkSurfaceKHR surface;
+
+        VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo;
+        memset(&surfaceCreateInfo, 0, sizeof(VkMacOSSurfaceCreateInfoMVK));
+        surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
+        surfaceCreateInfo.pNext = nullptr;
+        surfaceCreateInfo.flags = 0;
+        surfaceCreateInfo.pView = (__bridge void*)mtkView;
+
+        VkResult res = createMacOSSurfaceMVK(instance, &surfaceCreateInfo, nullptr, &surface);
+        if (VK_SUCCESS != res) {
+            return VK_NULL_HANDLE;
+        }
+
+        return surface;
+    };
+
+    auto canPresent = [](VkInstance instance, VkPhysicalDevice physDev, uint32_t queueFamilyIndex) {
+        return true;
+    };
+    WindowContext* context = new VulkanWindowContext_mac(mtkView, displayParams, createVkSurface,
+                                                         canPresent, instProc, devProc);
+    if (!context->isValid()) {
+        delete context;
+        [mtkView removeFromSuperview];
+        [mtkView release];
+        return nullptr;
+    }
+    return context;
+}
+
+}  // namespace VulkanWindowContextFactory
+
+}  // namespace sk_app
diff --git a/tools/sk_app/mac/WindowContextFactory_mac.h b/tools/sk_app/mac/WindowContextFactory_mac.h
index 196663c..136581e 100644
--- a/tools/sk_app/mac/WindowContextFactory_mac.h
+++ b/tools/sk_app/mac/WindowContextFactory_mac.h
@@ -22,10 +22,14 @@
     NSView*   fMainView;
 };
 
+#ifdef SK_VULKAN
+WindowContext* NewVulkanForMac(const MacWindowInfo&, const DisplayParams&);
+#else
 inline WindowContext* NewVulkanForMac(const MacWindowInfo&, const DisplayParams&) {
     // No Vulkan support on Mac.
     return nullptr;
 }
+#endif
 
 WindowContext* NewGLForMac(const MacWindowInfo&, const DisplayParams&);
 
diff --git a/tools/sk_app/mac/Window_mac.mm b/tools/sk_app/mac/Window_mac.mm
index efe86d1..89c975e 100644
--- a/tools/sk_app/mac/Window_mac.mm
+++ b/tools/sk_app/mac/Window_mac.mm
@@ -112,6 +112,11 @@
         case kRaster_BackendType:
             fWindowContext = NewRasterForMac(info, fRequestedDisplayParams);
             break;
+#ifdef SK_VULKAN
+        case kVulkan_BackendType:
+            fWindowContext = NewVulkanForMac(info, fRequestedDisplayParams);
+            break;
+#endif
 #ifdef SK_METAL
         case kMetal_BackendType:
             fWindowContext = NewMetalForMac(info, fRequestedDisplayParams);