Add VK_EXT_metal_surface extension support

VK_EXT_metal_surface is a similar extension to VK_MVK_macos_surface,
which is already supported.

Bug: chromium:1015454
Change-Id: I08d8e6b097d75236f724984b8c7d20251a63581f
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/37808
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Jonah Ryan-Davis <jonahr@google.com>
diff --git a/src/Vulkan/BUILD.gn b/src/Vulkan/BUILD.gn
index c42388d..5888f34 100644
--- a/src/Vulkan/BUILD.gn
+++ b/src/Vulkan/BUILD.gn
@@ -36,6 +36,7 @@
   } else if (is_mac) {
     defines = [
       "VK_USE_PLATFORM_MACOS_MVK=1",
+      "VK_USE_PLATFORM_METAL_EXT=1",
       "VK_EXPORT=__attribute__((visibility(\"default\")))",
     ]
   } else {
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index 4cc6a2d..636995b 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -103,6 +103,10 @@
     // VK_MVK_macos_surface
     MAKE_VULKAN_INSTANCE_ENTRY(vkCreateMacOSSurfaceMVK),
 #endif
+#ifdef VK_USE_PLATFORM_METAL_EXT
+    // VK_EXT_metal_surface
+    MAKE_VULKAN_INSTANCE_ENTRY(vkCreateMetalSurfaceEXT),
+#endif
 #ifdef VK_USE_PLATFORM_WIN32_KHR
 	// VK_KHR_win32_surface
 	MAKE_VULKAN_INSTANCE_ENTRY(vkCreateWin32SurfaceKHR),
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index ebb2aed..a42c59b 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -42,8 +42,8 @@
 #include "VkShaderModule.hpp"
 #include "VkRenderPass.hpp"
 
-#ifdef VK_USE_PLATFORM_MACOS_MVK
-#include "WSI/MacOSSurfaceMVK.h"
+#if defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_MACOS_MVK)
+#include "WSI/MetalSurface.h"
 #endif
 
 #ifdef VK_USE_PLATFORM_XCB_KHR
@@ -187,6 +187,9 @@
 #ifdef VK_USE_PLATFORM_MACOS_MVK
     { VK_MVK_MACOS_SURFACE_EXTENSION_NAME, VK_MVK_MACOS_SURFACE_SPEC_VERSION },
 #endif
+#ifdef VK_USE_PLATFORM_METAL_EXT
+    { VK_EXT_METAL_SURFACE_EXTENSION_NAME, VK_EXT_METAL_SURFACE_SPEC_VERSION },
+#endif
 #ifdef VK_USE_PLATFORM_WIN32_KHR
 	{ VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_SPEC_VERSION },
 #endif
@@ -2892,6 +2895,16 @@
 }
 #endif
 
+#ifdef VK_USE_PLATFORM_METAL_EXT
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateMetalSurfaceEXT(VkInstance instance, const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface)
+{
+    TRACE("(VkInstance instance = %p, VkMetalSurfaceCreateInfoEXT* pCreateInfo = %p, VkAllocationCallbacks* pAllocator = %p, VkSurface* pSurface = %p)",
+          instance, pCreateInfo, pAllocator, pSurface);
+
+    return vk::MetalSurfaceEXT::Create(pAllocator, pCreateInfo, pSurface);
+}
+#endif
+
 #ifdef VK_USE_PLATFORM_WIN32_KHR
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface)
 {
diff --git a/src/WSI/BUILD.gn b/src/WSI/BUILD.gn
index 15c21e2..17cf87b 100644
--- a/src/WSI/BUILD.gn
+++ b/src/WSI/BUILD.gn
@@ -42,8 +42,8 @@
 
   if (is_mac) {
     sources += [
-      "MacOSSurfaceMVK.mm",
-      "MacOSSurfaceMVK.h"
+      "MetalSurface.mm",
+      "MetalSurface.h",
     ]
     libs = [
       "Cocoa.framework",
diff --git a/src/WSI/MacOSSurfaceMVK.h b/src/WSI/MetalSurface.h
similarity index 61%
rename from src/WSI/MacOSSurfaceMVK.h
rename to src/WSI/MetalSurface.h
index a9950d9..29972a4 100644
--- a/src/WSI/MacOSSurfaceMVK.h
+++ b/src/WSI/MetalSurface.h
@@ -12,24 +12,29 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SWIFTSHADER_MACOSSURFACEMVK_HPP
-#define SWIFTSHADER_MACOSSURFACEMVK_HPP
+#ifndef SWIFTSHADER_METALSURFACE_HPP
+#define SWIFTSHADER_METALSURFACE_HPP
 
 #include "Vulkan/VkObject.hpp"
 #include "VkSurfaceKHR.hpp"
-#include "vulkan/vulkan_macos.h"
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+#	include "vulkan/vulkan_macos.h"
+#endif
+#ifdef VK_USE_PLATFORM_METAL_EXT
+#	include "vulkan/vulkan_metal.h"
+#endif
 
 namespace vk {
 
 class MetalLayer;
 
-class MacOSSurfaceMVK : public SurfaceKHR, public ObjectBase<MacOSSurfaceMVK, VkSurfaceKHR> {
+class MetalSurface : public SurfaceKHR, public ObjectBase<MetalSurface, VkSurfaceKHR> {
 public:
-    MacOSSurfaceMVK(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, void *mem);
+    MetalSurface(const void *pCreateInfo, void *mem);
 
     void destroySurface(const VkAllocationCallbacks *pAllocator) override;
 
-    static size_t ComputeRequiredAllocationSize(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo);
+    static size_t ComputeRequiredAllocationSize(const void *pCreateInfo);
 
     void getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const override;
 
@@ -37,9 +42,21 @@
     virtual void detachImage(PresentImage* image) override {}
     VkResult present(PresentImage* image) override;
 
-private:
+protected:
     MetalLayer* metalLayer = nullptr;
 };
 
+#ifdef VK_USE_PLATFORM_METAL_EXT
+class MetalSurfaceEXT : public MetalSurface {
+    MetalSurfaceEXT(const VkMetalSurfaceCreateInfoEXT *pCreateInfo, void *mem);
+};
+#endif
+
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+class MacOSSurfaceMVK : public MetalSurface {
+    MacOSSurfaceMVK(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, void *mem);
+};
+#endif
+
 }
-#endif //SWIFTSHADER_MACOSSURFACEMVK_HPP
+#endif //SWIFTSHADER_METALSURFACE_HPP
diff --git a/src/WSI/MacOSSurfaceMVK.mm b/src/WSI/MetalSurface.mm
similarity index 62%
rename from src/WSI/MacOSSurfaceMVK.mm
rename to src/WSI/MetalSurface.mm
index 2078c80..29dfa67 100644
--- a/src/WSI/MacOSSurfaceMVK.mm
+++ b/src/WSI/MetalSurface.mm
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "MacOSSurfaceMVK.h"
+#include "MetalSurface.h"
 #include "Vulkan/VkDeviceMemory.hpp"
 #include "Vulkan/VkImage.hpp"
 
@@ -25,7 +25,29 @@
 class MetalLayer
 {
 public:
-    void init(const void* pView) API_AVAILABLE(macosx(10.11))
+    void initWithLayer(const void* pLayer) API_AVAILABLE(macosx(10.11))
+    {
+        view = nullptr;
+        layer = nullptr;
+
+        id<NSObject> obj = (id<NSObject>)pLayer;
+
+        if(!NSThread.isMainThread)
+        {
+            UNREACHABLE("MetalLayer::init(): not called from main thread");
+        }
+        if ([obj isKindOfClass: [CAMetalLayer class]])
+        {
+            layer = (CAMetalLayer*)[obj retain];
+            layer.framebufferOnly = false;
+        }
+        else
+        {
+            UNREACHABLE("MetalLayer::init(): view doesn't have metal backed layer");
+        }
+    }
+
+    void initWithView(const void* pView) API_AVAILABLE(macosx(10.11))
     {
         view = nullptr;
         layer = nullptr;
@@ -34,22 +56,11 @@
 
         if([obj isKindOfClass: [NSView class]])
         {
-            if(!NSThread.isMainThread)
-            {
-                UNREACHABLE("MetalLayer::init(): not called from main thread");
-            }
-            view = (NSView*)[obj retain];
+            NSView* objView = (NSView*)[obj retain];
 
-            obj = view.layer;
-            if ([obj isKindOfClass: [CAMetalLayer class]])
-            {
-                layer = (CAMetalLayer*)[obj retain];
-                layer.framebufferOnly = false;
-            }
-            else
-            {
-                UNREACHABLE("MetalLayer::init(): view doesn't have metal backed layer");
-            }
+            initWithLayer(objView.layer);
+
+            view = objView;
         }
     }
 
@@ -59,7 +70,6 @@
         {
             [layer release];
         }
-
         if(view)
         {
             [view release];
@@ -97,13 +107,12 @@
     CAMetalLayer* layer API_AVAILABLE(macosx(10.11));
 };
 
-MacOSSurfaceMVK::MacOSSurfaceMVK(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, void *mem) API_AVAILABLE(macosx(10.11)) :
-    metalLayer(reinterpret_cast<MetalLayer*>(mem))
+MetalSurface::MetalSurface(const void *pCreateInfo, void *mem) : metalLayer(reinterpret_cast<MetalLayer*>(mem))
 {
-    metalLayer->init(pCreateInfo->pView);
+
 }
 
-void MacOSSurfaceMVK::destroySurface(const VkAllocationCallbacks *pAllocator) API_AVAILABLE(macosx(10.11))
+void MetalSurface::destroySurface(const VkAllocationCallbacks *pAllocator) API_AVAILABLE(macosx(10.11))
 {
     if(metalLayer)
     {
@@ -113,12 +122,12 @@
     vk::deallocate(metalLayer, pAllocator);
 }
 
-size_t MacOSSurfaceMVK::ComputeRequiredAllocationSize(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo) API_AVAILABLE(macosx(10.11))
+size_t MetalSurface::ComputeRequiredAllocationSize(const void *pCreateInfo) API_AVAILABLE(macosx(10.11))
 {
     return sizeof(MetalLayer);
 }
 
-void MacOSSurfaceMVK::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const API_AVAILABLE(macosx(10.11))
+void MetalSurface::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const API_AVAILABLE(macosx(10.11))
 {
     SurfaceKHR::getSurfaceCapabilities(pSurfaceCapabilities);
 
@@ -128,7 +137,7 @@
     pSurfaceCapabilities->maxImageExtent = extent;
 }
 
-VkResult MacOSSurfaceMVK::present(PresentImage* image) API_AVAILABLE(macosx(10.11))
+VkResult MetalSurface::present(PresentImage* image) API_AVAILABLE(macosx(10.11))
 {
     auto drawable = metalLayer->getNextDrawable();
     if(drawable)
@@ -143,4 +152,20 @@
     return VK_SUCCESS;
 }
 
+#ifdef VK_USE_PLATFORM_METAL_EXT
+MetalSurfaceEXT::MetalSurfaceEXT(const VkMetalSurfaceCreateInfoEXT *pCreateInfo, void *mem) API_AVAILABLE(macosx(10.11))
+ : MetalSurface(pCreateInfo, mem)
+{
+    metalLayer->initWithLayer(pCreateInfo->pLayer);
+}
+#endif
+
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+MacOSSurfaceMVK::MacOSSurfaceMVK(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, void *mem) API_AVAILABLE(macosx(10.11))
+ : MetalSurface(pCreateInfo, mem)
+{
+    metalLayer->initWithView(pCreateInfo->pView);
+}
+#endif
+
 }