Add support for SurfaceDescriptorFromWaylandSurface

Bug: dawn:1246
Change-Id: I0af28e1820ad8da2121a00bdef7202695d23bbf7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/75422
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b6733f5..287b903 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,6 +82,7 @@
 set(ENABLE_OPENGLES OFF)
 set(ENABLE_DESKTOP_GL OFF)
 set(ENABLE_VULKAN OFF)
+set(USE_WAYLAND OFF)
 set(USE_X11 OFF)
 set(BUILD_SAMPLES OFF)
 if (WIN32)
@@ -124,6 +125,7 @@
 option_if_not_defined(DAWN_ENABLE_OPENGLES "Enable compilation of the OpenGL ES backend" ${ENABLE_OPENGLES})
 option_if_not_defined(DAWN_ENABLE_VULKAN "Enable compilation of the Vulkan backend" ${ENABLE_VULKAN})
 option_if_not_defined(DAWN_ALWAYS_ASSERT "Enable assertions on all build types" OFF)
+option_if_not_defined(DAWN_USE_WAYLAND "Enable support for Wayland surface" ${USE_WAYLAND})
 option_if_not_defined(DAWN_USE_X11 "Enable support for X11 surface" ${USE_X11})
 
 option_if_not_defined(DAWN_BUILD_SAMPLES "Enables building Dawn's samples" ${BUILD_SAMPLES})
@@ -232,6 +234,9 @@
 if (DAWN_ENABLE_VULKAN)
     target_compile_definitions(dawn_internal_config INTERFACE "DAWN_ENABLE_BACKEND_VULKAN")
 endif()
+if (DAWN_USE_WAYLAND)
+    target_compile_definitions(dawn_internal_config INTERFACE "DAWN_USE_WAYLAND")
+endif()
 if (DAWN_USE_X11)
     target_compile_definitions(dawn_internal_config INTERFACE "DAWN_USE_X11")
 endif()
diff --git a/scripts/dawn_features.gni b/scripts/dawn_features.gni
index 234791c..57227de 100644
--- a/scripts/dawn_features.gni
+++ b/scripts/dawn_features.gni
@@ -19,10 +19,12 @@
   import("//build/config/sanitizers/sanitizers.gni")
 
   dawn_use_x11 = ozone_platform_x11
+  dawn_use_wayland = false
 } else {
   declare_args() {
     # Whether Dawn should enable X11 support.
     dawn_use_x11 = is_linux && !is_chromeos
+    dawn_use_wayland = false
   }
 }
 
diff --git a/src/dawn/common/BUILD.gn b/src/dawn/common/BUILD.gn
index 3ff8bde..a9ecded 100644
--- a/src/dawn/common/BUILD.gn
+++ b/src/dawn/common/BUILD.gn
@@ -80,6 +80,9 @@
     defines += [ "DAWN_ENABLE_BACKEND_VULKAN" ]
   }
 
+  if (dawn_use_wayland) {
+    defines += [ "DAWN_USE_WAYLAND" ]
+  }
   if (dawn_use_x11) {
     defines += [ "DAWN_USE_X11" ]
   }
diff --git a/src/dawn/common/vulkan_platform.h b/src/dawn/common/vulkan_platform.h
index c4bff86..848ee75 100644
--- a/src/dawn/common/vulkan_platform.h
+++ b/src/dawn/common/vulkan_platform.h
@@ -153,6 +153,12 @@
 #include "dawn/common/xlib_with_undefs.h"
 #endif  // defined(DAWN_USE_X11)
 
+#if defined(DAWN_USE_WAYLAND)
+#ifndef VK_USE_PLATFORM_WAYLAND_KHR
+#define VK_USE_PLATFORM_WAYLAND_KHR
+#endif
+#endif  // defined(DAWN_USE_WAYLAND)
+
 #if defined(DAWN_ENABLE_BACKEND_METAL)
 #ifndef VK_USE_PLATFORM_METAL_EXT
 #define VK_USE_PLATFORM_METAL_EXT
diff --git a/src/dawn/native/Surface.cpp b/src/dawn/native/Surface.cpp
index e93aa73..c340ccf 100644
--- a/src/dawn/native/Surface.cpp
+++ b/src/dawn/native/Surface.cpp
@@ -41,6 +41,9 @@
         case Surface::Type::MetalLayer:
             s->Append("MetalLayer");
             break;
+        case Surface::Type::WaylandSurface:
+            s->Append("WaylandSurface");
+            break;
         case Surface::Type::WindowsHWND:
             s->Append("WindowsHWND");
             break;
@@ -128,6 +131,18 @@
     }
 #endif  // defined(DAWN_PLATFORM_WINDOWS)
 
+#if defined(DAWN_USE_WAYLAND)
+    const SurfaceDescriptorFromWaylandSurface* waylandDesc = nullptr;
+    FindInChain(descriptor->nextInChain, &waylandDesc);
+    if (waylandDesc) {
+        // Unfortunately we can't check the validity of wayland objects. Only that they
+        // aren't nullptr.
+        DAWN_INVALID_IF(waylandDesc->display == nullptr, "Wayland display is nullptr.");
+        DAWN_INVALID_IF(waylandDesc->surface == nullptr, "Wayland surface is nullptr.");
+        return {};
+    }
+#endif  // defined(DAWN_USE_X11)
+
 #if defined(DAWN_USE_X11)
     const SurfaceDescriptorFromXlibWindow* xDesc = nullptr;
     FindInChain(descriptor->nextInChain, &xDesc);
@@ -165,6 +180,7 @@
     const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr;
     const SurfaceDescriptorFromWindowsCoreWindow* coreWindowDesc = nullptr;
     const SurfaceDescriptorFromWindowsSwapChainPanel* swapChainPanelDesc = nullptr;
+    const SurfaceDescriptorFromWaylandSurface* waylandDesc = nullptr;
     const SurfaceDescriptorFromXlibWindow* xDesc = nullptr;
     FindInChain(descriptor->nextInChain, &androidDesc);
     FindInChain(descriptor->nextInChain, &metalDesc);
@@ -178,6 +194,10 @@
     } else if (androidDesc) {
         mType = Type::AndroidWindow;
         mAndroidNativeWindow = androidDesc->window;
+    } else if (waylandDesc) {
+        mType = Type::WaylandSurface;
+        mWaylandDisplay = waylandDesc->display;
+        mWaylandSurface = waylandDesc->surface;
     } else if (hwndDesc) {
         mType = Type::WindowsHWND;
         mHInstance = hwndDesc->hinstance;
@@ -239,6 +259,16 @@
     return mMetalLayer;
 }
 
+void* Surface::GetWaylandDisplay() const {
+    ASSERT(mType == Type::WaylandSurface);
+    return mWaylandDisplay;
+}
+
+void* Surface::GetWaylandSurface() const {
+    ASSERT(mType == Type::WaylandSurface);
+    return mWaylandSurface;
+}
+
 void* Surface::GetHInstance() const {
     ASSERT(!IsError());
     ASSERT(mType == Type::WindowsHWND);
diff --git a/src/dawn/native/Surface.h b/src/dawn/native/Surface.h
index f01d96d..865d33b 100644
--- a/src/dawn/native/Surface.h
+++ b/src/dawn/native/Surface.h
@@ -55,6 +55,7 @@
     enum class Type {
         AndroidWindow,
         MetalLayer,
+        WaylandSurface,
         WindowsHWND,
         WindowsCoreWindow,
         WindowsSwapChainPanel,
@@ -69,6 +70,10 @@
     // Valid to call if the type is Android
     void* GetAndroidNativeWindow() const;
 
+    // Valid to call if the type is WaylandSurface
+    void* GetWaylandDisplay() const;
+    void* GetWaylandSurface() const;
+
     // Valid to call if the type is WindowsHWND
     void* GetHInstance() const;
     void* GetHWND() const;
@@ -99,6 +104,10 @@
     // ANativeWindow
     void* mAndroidNativeWindow = nullptr;
 
+    // Wayland
+    void* mWaylandDisplay = nullptr;
+    void* mWaylandSurface = nullptr;
+
     // WindowsHwnd
     void* mHInstance = nullptr;
     void* mHWND = nullptr;
diff --git a/src/dawn/native/vulkan/SwapChainVk.cpp b/src/dawn/native/vulkan/SwapChainVk.cpp
index 63de95e..9f35655 100644
--- a/src/dawn/native/vulkan/SwapChainVk.cpp
+++ b/src/dawn/native/vulkan/SwapChainVk.cpp
@@ -158,6 +158,26 @@
 
 #endif  // defined(DAWN_PLATFORM_ANDROID)
 
+#if defined(DAWN_USE_WAYLAND)
+        case Surface::Type::WaylandSurface: {
+            if (info.HasExt(InstanceExt::XlibSurface)) {
+                VkWaylandSurfaceCreateInfoKHR createInfo;
+                createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
+                createInfo.pNext = nullptr;
+                createInfo.flags = 0;
+                createInfo.display = static_cast<struct wl_display*>(surface->GetWaylandDisplay());
+                createInfo.surface = static_cast<struct wl_surface*>(surface->GetWaylandSurface());
+
+                VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+                DAWN_TRY(CheckVkSuccess(
+                    fn.CreateWaylandSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
+                    "CreateWaylandSurface"));
+                return vkSurface;
+            }
+            break;
+        }
+#endif  // defined(DAWN_USE_WAYLAND)
+
 #if defined(DAWN_USE_X11)
         case Surface::Type::XlibWindow: {
             if (info.HasExt(InstanceExt::XlibSurface)) {
diff --git a/src/dawn/native/vulkan/VulkanFunctions.cpp b/src/dawn/native/vulkan/VulkanFunctions.cpp
index 3734dac..1b629e6 100644
--- a/src/dawn/native/vulkan/VulkanFunctions.cpp
+++ b/src/dawn/native/vulkan/VulkanFunctions.cpp
@@ -188,6 +188,13 @@
     }
 #endif  // defined(DAWN_ENABLE_BACKEND_METAL)
 
+#if defined(DAWN_USE_WAYLAND)
+    if (globalInfo.HasExt(InstanceExt::WaylandSurface)) {
+        GET_INSTANCE_PROC(CreateWaylandSurfaceKHR);
+        GET_INSTANCE_PROC(GetPhysicalDeviceWaylandPresentationSupportKHR);
+    }
+#endif  // defined(DAWN_USE_WAYLAND)
+
 #if defined(DAWN_PLATFORM_WINDOWS)
     if (globalInfo.HasExt(InstanceExt::Win32Surface)) {
         GET_INSTANCE_PROC(CreateWin32SurfaceKHR);
diff --git a/src/dawn/native/vulkan/VulkanFunctions.h b/src/dawn/native/vulkan/VulkanFunctions.h
index 66732b8..0e26114 100644
--- a/src/dawn/native/vulkan/VulkanFunctions.h
+++ b/src/dawn/native/vulkan/VulkanFunctions.h
@@ -149,6 +149,13 @@
     VkFn<PFN_vkCreateMetalSurfaceEXT> CreateMetalSurfaceEXT = nullptr;
 #endif  // defined(DAWN_ENABLE_BACKEND_METAL)
 
+#if defined(DAWN_USE_WAYLAND)
+    // KHR_wayland_surface
+    PFN_vkCreateWaylandSurfaceKHR CreateWaylandSurfaceKHR = nullptr;
+    PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
+        GetPhysicalDeviceWaylandPresentationSupportKHR = nullptr;
+#endif  // defined(DAWN_USE_WAYLAND)
+
 #if defined(DAWN_PLATFORM_WINDOWS)
     // KHR_win32_surface
     VkFn<PFN_vkCreateWin32SurfaceKHR> CreateWin32SurfaceKHR = nullptr;
diff --git a/src/dawn/utils/GLFWUtils.cpp b/src/dawn/utils/GLFWUtils.cpp
index 5a1b4ba..b5c4a16 100644
--- a/src/dawn/utils/GLFWUtils.cpp
+++ b/src/dawn/utils/GLFWUtils.cpp
@@ -21,9 +21,13 @@
 
 #if defined(DAWN_PLATFORM_WINDOWS)
 #define GLFW_EXPOSE_NATIVE_WIN32
-#elif defined(DAWN_USE_X11)
+#endif
+#if defined(DAWN_USE_X11)
 #define GLFW_EXPOSE_NATIVE_X11
 #endif
+#if defined(DAWN_USE_WAYLAND)
+#define GLFW_EXPOSE_NATIVE_WAYLAND
+#endif
 #include "GLFW/glfw3native.h"
 
 namespace utils {
@@ -59,28 +63,45 @@
     return surface;
 }
 
+// SetupWindowAndGetSurfaceDescriptorCocoa defined in GLFWUtils_metal.mm
+std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(GLFWwindow* window);
+
+std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow* window) {
+    switch (glfwGetPlatform()) {
 #if defined(DAWN_PLATFORM_WINDOWS)
-std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow* window) {
-    std::unique_ptr<wgpu::SurfaceDescriptorFromWindowsHWND> desc =
-        std::make_unique<wgpu::SurfaceDescriptorFromWindowsHWND>();
-    desc->hwnd = glfwGetWin32Window(window);
-    desc->hinstance = GetModuleHandle(nullptr);
-    return std::move(desc);
-}
-#elif defined(DAWN_USE_X11)
-std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow* window) {
-    std::unique_ptr<wgpu::SurfaceDescriptorFromXlibWindow> desc =
-        std::make_unique<wgpu::SurfaceDescriptorFromXlibWindow>();
-    desc->display = glfwGetX11Display();
-    desc->window = glfwGetX11Window(window);
-    return std::move(desc);
-}
-#elif defined(DAWN_ENABLE_BACKEND_METAL)
-// SetupWindowAndGetSurfaceDescriptor defined in GLFWUtils_metal.mm
-#else
-std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow*) {
-    return nullptr;
-}
+        case GLFW_PLATFORM_WIN32: {
+            std::unique_ptr<wgpu::SurfaceDescriptorFromWindowsHWND> desc =
+                std::make_unique<wgpu::SurfaceDescriptorFromWindowsHWND>();
+            desc->hwnd = glfwGetWin32Window(window);
+            desc->hinstance = GetModuleHandle(nullptr);
+            return std::move(desc);
+        }
 #endif
+#if defined(DAWN_ENABLE_BACKEND_METAL)
+        case GLFW_PLATFORM_COCOA:
+            return SetupWindowAndGetSurfaceDescriptorCocoa(window);
+#endif
+#if defined(DAWN_USE_WAYLAND)
+        case GLFW_PLATFORM_WAYLAND: {
+            std::unique_ptr<wgpu::SurfaceDescriptorFromWaylandSurface> desc =
+                std::make_unique<wgpu::SurfaceDescriptorFromWaylandSurface>();
+            desc->display = glfwGetWaylandDisplay();
+            desc->surface = glfwGetWaylandWindow(window);
+            return std::move(desc);
+        }
+#endif
+#if defined(DAWN_USE_X11)
+        case GLFW_PLATFORM_X11: {
+            std::unique_ptr<wgpu::SurfaceDescriptorFromXlibWindow> desc =
+                std::make_unique<wgpu::SurfaceDescriptorFromXlibWindow>();
+            desc->display = glfwGetX11Display();
+            desc->window = glfwGetX11Window(window);
+            return std::move(desc);
+        }
+#endif
+        default:
+            return nullptr;
+    }
+}
 
 }  // namespace utils
diff --git a/src/dawn/utils/GLFWUtils_metal.mm b/src/dawn/utils/GLFWUtils_metal.mm
index 0762a3d..d07eeca 100644
--- a/src/dawn/utils/GLFWUtils_metal.mm
+++ b/src/dawn/utils/GLFWUtils_metal.mm
@@ -28,7 +28,7 @@
 
 namespace utils {
 
-std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow* window) {
+std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(GLFWwindow* window) {
     if (@available(macOS 10.11, *)) {
         NSWindow* nsWindow = glfwGetCocoaWindow(window);
         NSView* view = [nsWindow contentView];