Introduce wgpu::Surface and implement it for HWND, X11 and Metal

This is another step to implement webgpu.h swapchains, Surface is
essentially a union type of all the types of windows that can be used to
create swapchains.

Changes to allow implementing wgpu::Surface and test its creation are:

 - Add GLFWUtils.cpp/.h/_metal.mm  that contains helpers used to use
WebGPU with GLFW. This deprecates BackendBinding.h that will be removed
when the NXT swapchain is removed.
 - Add a `dawn_use_x11` GN variable to factor all the places in BUILD.gn
where we checked whether we should use X11.
 - Add a `supports_glfw_for_windowing` GN variable in the main BUILD.gn
file to control which configuration tests and samples using GLFW can be
built.
 - Add a ObjCUtils.h to contain some ObjC functionality that we'd need
in files that otherwise would be C++ (so that they can be compiled on
all platforms).

Bug: dawn:269

Change-Id: I25548142a1d1d1f05b0f4d71aa3bdc4698d19622
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15081
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/Surface.cpp b/src/dawn_native/Surface.cpp
new file mode 100644
index 0000000..0d02144
--- /dev/null
+++ b/src/dawn_native/Surface.cpp
@@ -0,0 +1,172 @@
+// Copyright 2020 the Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn_native/Surface.h"
+
+#include "common/Platform.h"
+#include "dawn_native/Instance.h"
+
+#if defined(DAWN_PLATFORM_WINDOWS)
+#    include "common/windows_with_undefs.h"
+#endif  // DAWN_PLATFORM_WINDOWS
+
+#if defined(DAWN_USE_X11)
+#    include "common/xlib_with_undefs.h"
+#endif  // defined(DAWN_USE_X11)
+
+namespace dawn_native {
+
+#if defined(DAWN_ENABLE_BACKEND_METAL)
+    bool InheritsFromCAMetalLayer(void* obj);
+#endif  // defined(DAWN_ENABLE_BACKEND_METAL)
+
+    MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance,
+                                         const SurfaceDescriptor* descriptor) {
+        // TODO(cwallez@chromium.org): Have some type of helper to iterate over all the chained
+        // structures.
+        if (descriptor->nextInChain == nullptr) {
+            return DAWN_VALIDATION_ERROR("Surface cannot be created with just the base descriptor");
+        }
+
+        const ChainedStruct* chainedDescriptor = descriptor->nextInChain;
+        if (chainedDescriptor->nextInChain != nullptr) {
+            return DAWN_VALIDATION_ERROR("Cannot specify two windows for a single surface");
+        }
+
+        switch (chainedDescriptor->sType) {
+#if defined(DAWN_ENABLE_BACKEND_METAL)
+            case wgpu::SType::SurfaceDescriptorFromMetalLayer: {
+                const SurfaceDescriptorFromMetalLayer* metalDesc =
+                    static_cast<const SurfaceDescriptorFromMetalLayer*>(chainedDescriptor);
+
+                // Check that the layer is a CAMetalLayer (or a derived class).
+                if (!InheritsFromCAMetalLayer(metalDesc->layer)) {
+                    return DAWN_VALIDATION_ERROR("layer must be a CAMetalLayer");
+                }
+            } break;
+#endif  // defined(DAWN_ENABLE_BACKEND_METAL)
+
+#if defined(DAWN_PLATFORM_WINDOWS)
+            case wgpu::SType::SurfaceDescriptorFromWindowsHWND: {
+                const SurfaceDescriptorFromWindowsHWND* hwndDesc =
+                    static_cast<const SurfaceDescriptorFromWindowsHWND*>(chainedDescriptor);
+
+                // It is not possible to validate an HINSTANCE.
+
+                // Validate the hwnd using the windows.h IsWindow function.
+                if (IsWindow(static_cast<HWND>(hwndDesc->hwnd)) == 0) {
+                    return DAWN_VALIDATION_ERROR("Invalid HWND");
+                }
+            } break;
+#endif  // defined(DAWN_PLATFORM_WINDOWS)
+
+#if defined(DAWN_USE_X11)
+            case wgpu::SType::SurfaceDescriptorFromXlib: {
+                const SurfaceDescriptorFromXlib* xDesc =
+                    static_cast<const SurfaceDescriptorFromXlib*>(chainedDescriptor);
+
+                // It is not possible to validate an X Display.
+
+                // Check the validity of the window by calling a getter function on the window that
+                // returns a status code. If the window is bad the call return a status of zero. We
+                // need to set a temporary X11 error handler while doing this because the default
+                // X11 error handler exits the program on any error.
+                XErrorHandler oldErrorHandler =
+                    XSetErrorHandler([](Display*, XErrorEvent*) { return 0; });
+                XWindowAttributes attributes;
+                int status = XGetWindowAttributes(reinterpret_cast<Display*>(xDesc->display),
+                                                  xDesc->window, &attributes);
+                XSetErrorHandler(oldErrorHandler);
+
+                if (status == 0) {
+                    return DAWN_VALIDATION_ERROR("Invalid X Window");
+                }
+            } break;
+#endif  // defined(DAWN_USE_X11)
+
+            default:
+                return DAWN_VALIDATION_ERROR("Unsupported sType");
+        }
+
+        return {};
+    }
+
+    Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor)
+        : mInstance(instance) {
+        ASSERT(descriptor->nextInChain != nullptr);
+        const ChainedStruct* chainedDescriptor = descriptor->nextInChain;
+
+        switch (chainedDescriptor->sType) {
+            case wgpu::SType::SurfaceDescriptorFromMetalLayer: {
+                const SurfaceDescriptorFromMetalLayer* metalDesc =
+                    static_cast<const SurfaceDescriptorFromMetalLayer*>(chainedDescriptor);
+                mType = Type::MetalLayer;
+                mMetalLayer = metalDesc->layer;
+            } break;
+
+            case wgpu::SType::SurfaceDescriptorFromWindowsHWND: {
+                const SurfaceDescriptorFromWindowsHWND* hwndDesc =
+                    static_cast<const SurfaceDescriptorFromWindowsHWND*>(chainedDescriptor);
+                mType = Type::WindowsHWND;
+                mHInstance = hwndDesc->hinstance;
+                mHWND = hwndDesc->hwnd;
+            } break;
+
+            case wgpu::SType::SurfaceDescriptorFromXlib: {
+                const SurfaceDescriptorFromXlib* xDesc =
+                    static_cast<const SurfaceDescriptorFromXlib*>(chainedDescriptor);
+                mType = Type::Xlib;
+                mXDisplay = xDesc->display;
+                mXWindow = xDesc->window;
+            } break;
+
+            default:
+                UNREACHABLE();
+        }
+    }
+
+    Surface::~Surface() = default;
+
+    InstanceBase* Surface::GetInstance() {
+        return mInstance.Get();
+    }
+
+    Surface::Type Surface::GetType() const {
+        return mType;
+    }
+
+    void* Surface::GetMetalLayer() const {
+        ASSERT(mType == Type::MetalLayer);
+        return mMetalLayer;
+    }
+
+    void* Surface::GetHInstance() const {
+        ASSERT(mType == Type::WindowsHWND);
+        return mHInstance;
+    }
+    void* Surface::GetHWND() const {
+        ASSERT(mType == Type::WindowsHWND);
+        return mHWND;
+    }
+
+    void* Surface::GetXDisplay() const {
+        ASSERT(mType == Type::Xlib);
+        return mXDisplay;
+    }
+    uint32_t Surface::GetXWindow() const {
+        ASSERT(mType == Type::Xlib);
+        return mXWindow;
+    }
+
+}  // namespace dawn_native