Support Vulkan on Linux as well as Windows.

Refactor display and surface classes into Win32 and Linux parts and
add Linux parts to gn and gyp builds.

BUG=angleproject:1668

Change-Id: I2a7d29c35f4f42fa0035bd97938d3770f3627672
Reviewed-on: https://chromium-review.googlesource.com/412426
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/angle.gyp b/src/angle.gyp
index e55ae92..e2b0f9b 100644
--- a/src/angle.gyp
+++ b/src/angle.gyp
@@ -35,6 +35,7 @@
             ['OS=="linux" and use_x11==1 and chromeos==0',
             {
                 'angle_enable_gl%': 1,
+                'angle_enable_vulkan%': 1,
             }],
             ['OS=="mac"',
             {
diff --git a/src/common/Optional.h b/src/common/Optional.h
index 5a79048..060ef14 100644
--- a/src/common/Optional.h
+++ b/src/common/Optional.h
@@ -10,6 +10,8 @@
 #ifndef COMMON_OPTIONAL_H_
 #define COMMON_OPTIONAL_H_
 
+#include <utility>
+
 template <class T>
 struct Optional
 {
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index bd7d499..d67bdd2 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -59,7 +59,13 @@
 #endif  // defined(ANGLE_ENABLE_NULL)
 
 #if defined(ANGLE_ENABLE_VULKAN)
-#include "libANGLE/renderer/vulkan/DisplayVk.h"
+#if defined(ANGLE_PLATFORM_WINDOWS)
+#include "libANGLE/renderer/vulkan/win32/DisplayVkWin32.h"
+#elif defined(ANGLE_PLATFORM_LINUX)
+#include "libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h"
+#else
+#error Unsupported Vulkan platform.
+#endif
 #endif  // defined(ANGLE_ENABLE_VULKAN)
 
 namespace egl
@@ -199,7 +205,13 @@
 
         case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
 #if defined(ANGLE_ENABLE_VULKAN)
-            impl = new rx::DisplayVk(state);
+#if defined(ANGLE_PLATFORM_WINDOWS)
+            impl = new rx::DisplayVkWin32(state);
+#elif defined(ANGLE_PLATFORM_LINUX)
+            impl = new rx::DisplayVkXcb(state);
+#else
+#error Unsupported Vulkan platform.
+#endif
 #else
             // No display available
             UNREACHABLE();
diff --git a/src/libANGLE/renderer/vulkan/DisplayVk.cpp b/src/libANGLE/renderer/vulkan/DisplayVk.cpp
index 0d8c731..eccc78e 100644
--- a/src/libANGLE/renderer/vulkan/DisplayVk.cpp
+++ b/src/libANGLE/renderer/vulkan/DisplayVk.cpp
@@ -31,7 +31,8 @@
 {
     ASSERT(!mRenderer && display != nullptr);
     mRenderer.reset(new RendererVk());
-    return mRenderer->initialize(display->getAttributeMap()).toEGL(EGL_NOT_INITIALIZED);
+    return mRenderer->initialize(display->getAttributeMap(), getWSIName())
+        .toEGL(EGL_NOT_INITIALIZED);
 }
 
 void DisplayVk::terminate()
@@ -103,12 +104,6 @@
     return egl::Error(EGL_BAD_ACCESS);
 }
 
-bool DisplayVk::isValidNativeWindow(EGLNativeWindowType window) const
-{
-    // TODO(jmadill): Cross-platform this.
-    return (IsWindow(window) == TRUE);
-}
-
 std::string DisplayVk::getVendorString() const
 {
     std::string vendorString = "Google Inc.";
@@ -146,7 +141,7 @@
     EGLint width  = attribs.getAsInt(EGL_WIDTH, 0);
     EGLint height = attribs.getAsInt(EGL_HEIGHT, 0);
 
-    return new WindowSurfaceVk(state, window, width, height);
+    return createWindowSurfaceVk(state, window, width, height);
 }
 
 SurfaceImpl *DisplayVk::createPbufferSurface(const egl::SurfaceState &state,
diff --git a/src/libANGLE/renderer/vulkan/DisplayVk.h b/src/libANGLE/renderer/vulkan/DisplayVk.h
index 398088d..f514efd 100644
--- a/src/libANGLE/renderer/vulkan/DisplayVk.h
+++ b/src/libANGLE/renderer/vulkan/DisplayVk.h
@@ -34,8 +34,6 @@
     bool testDeviceLost() override;
     egl::Error restoreLostDevice() override;
 
-    bool isValidNativeWindow(EGLNativeWindowType window) const override;
-
     std::string getVendorString() const override;
 
     egl::Error getDevice(DeviceImpl **device) override;
@@ -71,7 +69,13 @@
 
     RendererVk *getRenderer() const { return mRenderer.get(); }
 
+    virtual const char *getWSIName() const = 0;
+
   private:
+    virtual SurfaceImpl *createWindowSurfaceVk(const egl::SurfaceState &state,
+                                               EGLNativeWindowType window,
+                                               EGLint width,
+                                               EGLint height) = 0;
     void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
     void generateCaps(egl::Caps *outCaps) const override;
 
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index c83c4a7..1f51cd6 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -153,7 +153,7 @@
     mPhysicalDevice = VK_NULL_HANDLE;
 }
 
-vk::Error RendererVk::initialize(const egl::AttributeMap &attribs)
+vk::Error RendererVk::initialize(const egl::AttributeMap &attribs, const char *wsiName)
 {
 #if !defined(NDEBUG)
     // Validation layers enabled by default in Debug.
@@ -229,11 +229,7 @@
 
     std::vector<const char *> enabledInstanceExtensions;
     enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
-#if defined(ANGLE_PLATFORM_WINDOWS)
-    enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
-#else
-#error Unsupported Vulkan platform.
-#endif  // defined(ANGLE_PLATFORM_WINDOWS)
+    enabledInstanceExtensions.push_back(wsiName);
 
     // TODO(jmadill): Should be able to continue initialization if debug report ext missing.
     if (mEnableValidationLayers)
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.h b/src/libANGLE/renderer/vulkan/RendererVk.h
index 53b9d0b..48d3933 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.h
+++ b/src/libANGLE/renderer/vulkan/RendererVk.h
@@ -37,7 +37,7 @@
     RendererVk();
     ~RendererVk();
 
-    vk::Error initialize(const egl::AttributeMap &attribs);
+    vk::Error initialize(const egl::AttributeMap &attribs, const char *wsiName);
 
     std::string getVendorString() const;
     std::string getRendererDescription() const;
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
index 5f07421..09de86e 100644
--- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
@@ -152,6 +152,7 @@
     : SurfaceImpl(surfaceState),
       mNativeWindowType(window),
       mSurface(VK_NULL_HANDLE),
+      mInstance(VK_NULL_HANDLE),
       mSwapchain(VK_NULL_HANDLE),
       mRenderTarget(),
       mCurrentSwapchainImageIndex(0)
@@ -217,15 +218,8 @@
 
 vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
 {
-    // TODO(jmadill): Make this platform-specific.
-    VkWin32SurfaceCreateInfoKHR createInfo;
-
-    createInfo.sType     = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
-    createInfo.pNext     = nullptr;
-    createInfo.flags     = 0;
-    createInfo.hinstance = GetModuleHandle(nullptr);
-    createInfo.hwnd      = mNativeWindowType;
-    ANGLE_VK_TRY(vkCreateWin32SurfaceKHR(renderer->getInstance(), &createInfo, nullptr, &mSurface));
+    gl::Extents windowSize;
+    ANGLE_TRY_RESULT(createSurfaceVk(renderer), windowSize);
 
     uint32_t presentQueue = 0;
     ANGLE_TRY_RESULT(renderer->selectPresentQueueForSurface(mSurface), presentQueue);
@@ -247,16 +241,13 @@
     {
         ASSERT(surfaceCaps.currentExtent.height == 0xFFFFFFFFu);
 
-        RECT rect;
-        ANGLE_VK_CHECK(GetClientRect(mNativeWindowType, &rect) == TRUE,
-                       VK_ERROR_INITIALIZATION_FAILED);
         if (mRenderTarget.extents.width == 0)
         {
-            width = static_cast<uint32_t>(rect.right - rect.left);
+            width = windowSize.width;
         }
         if (mRenderTarget.extents.height == 0)
         {
-            height = static_cast<uint32_t>(rect.bottom - rect.top);
+            height = windowSize.height;
         }
     }
 
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.h b/src/libANGLE/renderer/vulkan/SurfaceVk.h
index ff177a9..e42696b 100644
--- a/src/libANGLE/renderer/vulkan/SurfaceVk.h
+++ b/src/libANGLE/renderer/vulkan/SurfaceVk.h
@@ -88,13 +88,17 @@
         VkDevice device,
         const vk::RenderPass &compatibleRenderPass);
 
+  protected:
+    EGLNativeWindowType mNativeWindowType;
+    VkSurfaceKHR mSurface;
+    VkInstance mInstance;
+
   private:
+    virtual vk::ErrorOrResult<gl::Extents> createSurfaceVk(RendererVk *renderer) = 0;
     vk::Error initializeImpl(RendererVk *renderer);
     vk::Error nextSwapchainImage(RendererVk *renderer);
     vk::Error swapImpl(RendererVk *renderer);
 
-    EGLNativeWindowType mNativeWindowType;
-    VkSurfaceKHR mSurface;
     VkSwapchainKHR mSwapchain;
 
     RenderTargetVk mRenderTarget;
diff --git a/src/libANGLE/renderer/vulkan/renderervk_utils.h b/src/libANGLE/renderer/vulkan/renderervk_utils.h
index 7a9c1b5..bf2c28f 100644
--- a/src/libANGLE/renderer/vulkan/renderervk_utils.h
+++ b/src/libANGLE/renderer/vulkan/renderervk_utils.h
@@ -10,6 +10,8 @@
 #ifndef LIBANGLE_RENDERER_VULKAN_RENDERERVK_UTILS_H_
 #define LIBANGLE_RENDERER_VULKAN_RENDERERVK_UTILS_H_
 
+#include <limits>
+
 #include <vulkan/vulkan.h>
 
 #include "common/debug.h"
diff --git a/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.cpp b/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.cpp
new file mode 100644
index 0000000..48a7bba
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.cpp
@@ -0,0 +1,41 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// DisplayVkWin32.cpp:
+//    Implements the class methods for DisplayVkWin32.
+//
+
+#include "libANGLE/renderer/vulkan/win32/DisplayVkWin32.h"
+
+#include <vulkan/vulkan.h>
+
+#include "libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h"
+
+namespace rx
+{
+
+DisplayVkWin32::DisplayVkWin32(const egl::DisplayState &state) : DisplayVk(state)
+{
+}
+
+bool DisplayVkWin32::isValidNativeWindow(EGLNativeWindowType window) const
+{
+    return (IsWindow(window) == TRUE);
+}
+
+SurfaceImpl *DisplayVkWin32::createWindowSurfaceVk(const egl::SurfaceState &state,
+                                                   EGLNativeWindowType window,
+                                                   EGLint width,
+                                                   EGLint height)
+{
+    return new WindowSurfaceVkWin32(state, window, width, height);
+}
+
+const char *DisplayVkWin32::getWSIName() const
+{
+    return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
+}
+
+}  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.h b/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.h
new file mode 100644
index 0000000..5942155
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.h
@@ -0,0 +1,34 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// DisplayVkWin32.h:
+//    Defines the class interface for DisplayVkWin32, implementing DisplayVk for Windows.
+//
+
+#ifndef LIBANGLE_RENDERER_VULKAN_WIN32_DISPLAYVKWIN32_H_
+#define LIBANGLE_RENDERER_VULKAN_WIN32_DISPLAYVKWIN32_H_
+
+#include "libANGLE/renderer/vulkan/DisplayVk.h"
+
+namespace rx
+{
+class DisplayVkWin32 : public DisplayVk
+{
+  public:
+    DisplayVkWin32(const egl::DisplayState &state);
+
+    bool isValidNativeWindow(EGLNativeWindowType window) const override;
+
+    SurfaceImpl *createWindowSurfaceVk(const egl::SurfaceState &state,
+                                       EGLNativeWindowType window,
+                                       EGLint width,
+                                       EGLint height) override;
+
+    const char *getWSIName() const override;
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_VULKAN_WIN32_DISPLAYVKWIN32_H_
diff --git a/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.cpp b/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.cpp
new file mode 100644
index 0000000..b9de8d8
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.cpp
@@ -0,0 +1,42 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// WindowSurfaceVkWin32.cpp:
+//    Implements the class methods for WindowSurfaceVkWin32.
+//
+
+#include "libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h"
+
+#include "libANGLE/renderer/vulkan/RendererVk.h"
+
+namespace rx
+{
+
+WindowSurfaceVkWin32::WindowSurfaceVkWin32(const egl::SurfaceState &surfaceState,
+                                           EGLNativeWindowType window,
+                                           EGLint width,
+                                           EGLint height)
+    : WindowSurfaceVk(surfaceState, window, width, height)
+{
+}
+
+vk::ErrorOrResult<gl::Extents> WindowSurfaceVkWin32::createSurfaceVk(RendererVk *renderer)
+{
+    VkWin32SurfaceCreateInfoKHR createInfo;
+
+    createInfo.sType     = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+    createInfo.pNext     = nullptr;
+    createInfo.flags     = 0;
+    createInfo.hinstance = GetModuleHandle(nullptr);
+    createInfo.hwnd      = mNativeWindowType;
+    ANGLE_VK_TRY(vkCreateWin32SurfaceKHR(renderer->getInstance(), &createInfo, nullptr, &mSurface));
+
+    RECT rect;
+    ANGLE_VK_CHECK(GetClientRect(mNativeWindowType, &rect) == TRUE, VK_ERROR_INITIALIZATION_FAILED);
+
+    return gl::Extents(rect.right - rect.left, rect.bottom - rect.top, 0);
+}
+
+}  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h b/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h
new file mode 100644
index 0000000..5d0c978
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h
@@ -0,0 +1,32 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// WindowSurfaceVkWin32.h:
+//    Defines the class interface for WindowSurfaceVkWin32, implementing WindowSurfaceVk.
+//
+
+#ifndef LIBANGLE_RENDERER_VULKAN_WIN32_WINDOWSURFACEVKWIN32_H_
+#define LIBANGLE_RENDERER_VULKAN_WIN32_WINDOWSURFACEVKWIN32_H_
+
+#include "libANGLE/renderer/vulkan/SurfaceVk.h"
+
+namespace rx
+{
+
+class WindowSurfaceVkWin32 : public WindowSurfaceVk
+{
+  public:
+    WindowSurfaceVkWin32(const egl::SurfaceState &surfaceState,
+                         EGLNativeWindowType window,
+                         EGLint width,
+                         EGLint height);
+
+  private:
+    vk::ErrorOrResult<gl::Extents> createSurfaceVk(RendererVk *renderer) override;
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_VULKAN_WIN32_WINDOWSURFACEVKWIN32_H_
diff --git a/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.cpp b/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.cpp
new file mode 100644
index 0000000..bd4d013
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// DisplayVkXcb.cpp:
+//    Implements the class methods for DisplayVkXcb.
+//
+
+#include "libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h"
+
+#include <xcb/xcb.h>
+
+#include "libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h"
+
+namespace rx
+{
+
+DisplayVkXcb::DisplayVkXcb(const egl::DisplayState &state)
+    : DisplayVk(state), mXcbConnection(nullptr)
+{
+}
+
+egl::Error DisplayVkXcb::initialize(egl::Display *display)
+{
+    mXcbConnection = xcb_connect(nullptr, nullptr);
+    if (mXcbConnection == nullptr)
+    {
+        return egl::Error(EGL_NOT_INITIALIZED);
+    }
+    return DisplayVk::initialize(display);
+}
+
+void DisplayVkXcb::terminate()
+{
+    ASSERT(mXcbConnection != nullptr);
+    xcb_disconnect(mXcbConnection);
+    mXcbConnection = nullptr;
+    DisplayVk::terminate();
+}
+
+bool DisplayVkXcb::isValidNativeWindow(EGLNativeWindowType window) const
+{
+    // There doesn't appear to be an xcb function explicitly for checking the validity of a
+    // window ID, but xcb_query_tree_reply will return nullptr if the window doesn't exist.
+    xcb_query_tree_cookie_t cookie = xcb_query_tree(mXcbConnection, window);
+    xcb_query_tree_reply_t *reply  = xcb_query_tree_reply(mXcbConnection, cookie, nullptr);
+    if (reply)
+    {
+        free(reply);
+        return true;
+    }
+    return false;
+}
+
+SurfaceImpl *DisplayVkXcb::createWindowSurfaceVk(const egl::SurfaceState &state,
+                                                 EGLNativeWindowType window,
+                                                 EGLint width,
+                                                 EGLint height)
+{
+    return new WindowSurfaceVkXcb(state, window, width, height, mXcbConnection);
+}
+
+const char *DisplayVkXcb::getWSIName() const
+{
+    return VK_KHR_XCB_SURFACE_EXTENSION_NAME;
+}
+
+}  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h b/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h
new file mode 100644
index 0000000..eea95bb
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h
@@ -0,0 +1,43 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// DisplayVkXcb.h:
+//    Defines the class interface for DisplayVkXcb, implementing DisplayVk for X via XCB.
+//
+
+#ifndef LIBANGLE_RENDERER_VULKAN_XCB_DISPLAYVKXCB_H_
+#define LIBANGLE_RENDERER_VULKAN_XCB_DISPLAYVKXCB_H_
+
+#include "libANGLE/renderer/vulkan/DisplayVk.h"
+
+struct xcb_connection_t;
+
+namespace rx
+{
+
+class DisplayVkXcb : public DisplayVk
+{
+  public:
+    DisplayVkXcb(const egl::DisplayState &state);
+
+    egl::Error initialize(egl::Display *display) override;
+    void terminate() override;
+
+    bool isValidNativeWindow(EGLNativeWindowType window) const override;
+
+    SurfaceImpl *createWindowSurfaceVk(const egl::SurfaceState &state,
+                                       EGLNativeWindowType window,
+                                       EGLint width,
+                                       EGLint height) override;
+
+    const char *getWSIName() const override;
+
+  private:
+    xcb_connection_t *mXcbConnection;
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_VULKAN_XCB_DISPLAYVKXCB_H_
diff --git a/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.cpp b/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.cpp
new file mode 100644
index 0000000..b486b74
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.cpp
@@ -0,0 +1,45 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// WindowSurfaceVkXcb.cpp:
+//    Implements the class methods for WindowSurfaceVkXcb.
+//
+
+#include "libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h"
+
+#include "libANGLE/renderer/vulkan/RendererVk.h"
+
+namespace rx
+{
+
+WindowSurfaceVkXcb::WindowSurfaceVkXcb(const egl::SurfaceState &surfaceState,
+                                       EGLNativeWindowType window,
+                                       EGLint width,
+                                       EGLint height,
+                                       xcb_connection_t *conn)
+    : WindowSurfaceVk(surfaceState, window, width, height), mXcbConnection(conn)
+{
+}
+
+vk::ErrorOrResult<gl::Extents> WindowSurfaceVkXcb::createSurfaceVk(RendererVk *renderer)
+{
+    VkXcbSurfaceCreateInfoKHR createInfo;
+
+    createInfo.sType      = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
+    createInfo.pNext      = nullptr;
+    createInfo.flags      = 0;
+    createInfo.connection = mXcbConnection;
+    createInfo.window     = mNativeWindowType;
+    ANGLE_VK_TRY(vkCreateXcbSurfaceKHR(renderer->getInstance(), &createInfo, nullptr, &mSurface));
+
+    xcb_get_geometry_cookie_t cookie = xcb_get_geometry(mXcbConnection, mNativeWindowType);
+    xcb_get_geometry_reply_t *reply  = xcb_get_geometry_reply(mXcbConnection, cookie, nullptr);
+    ASSERT(reply);
+    gl::Extents result(reply->width, reply->height, 0);
+    free(reply);
+    return result;
+}
+
+}  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h b/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h
new file mode 100644
index 0000000..1d3cdc0
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h
@@ -0,0 +1,37 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// WindowSurfaceVkXcb.h:
+//    Defines the class interface for WindowSurfaceVkXcb, implementing WindowSurfaceVk.
+//
+
+#ifndef LIBANGLE_RENDERER_VULKAN_XCB_WINDOWSURFACEVKXCB_H_
+#define LIBANGLE_RENDERER_VULKAN_XCB_WINDOWSURFACEVKXCB_H_
+
+#include "libANGLE/renderer/vulkan/SurfaceVk.h"
+
+struct xcb_connection_t;
+
+namespace rx
+{
+
+class WindowSurfaceVkXcb : public WindowSurfaceVk
+{
+  public:
+    WindowSurfaceVkXcb(const egl::SurfaceState &surfaceState,
+                       EGLNativeWindowType window,
+                       EGLint width,
+                       EGLint height,
+                       xcb_connection_t *conn);
+
+  private:
+    vk::ErrorOrResult<gl::Extents> createSurfaceVk(RendererVk *renderer) override;
+
+    xcb_connection_t *mXcbConnection;
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_VULKAN_XCB_WINDOWSURFACEVKXCB_H_
diff --git a/src/libGLESv2.gypi b/src/libGLESv2.gypi
index 712c5e6..4c184d8 100644
--- a/src/libGLESv2.gypi
+++ b/src/libGLESv2.gypi
@@ -683,6 +683,20 @@
             'libANGLE/renderer/vulkan/renderervk_utils.h',
             'libANGLE/renderer/vulkan/vk_format_table_autogen.cpp',
         ],
+        'libangle_vulkan_win32_sources':
+        [
+            'libANGLE/renderer/vulkan/win32/DisplayVkWin32.cpp',
+            'libANGLE/renderer/vulkan/win32/DisplayVkWin32.h',
+            'libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.cpp',
+            'libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h',
+        ],
+        'libangle_vulkan_xcb_sources':
+        [
+            'libANGLE/renderer/vulkan/xcb/DisplayVkXcb.cpp',
+            'libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h',
+            'libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.cpp',
+            'libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h',
+        ],
         'libangle_null_sources':
         [
             'libANGLE/renderer/null/BufferNULL.cpp',
@@ -1009,10 +1023,10 @@
                             ],
                             'link_settings': {
                                 'ldflags': [
-                                    '<!@(<(pkg-config) --libs-only-L --libs-only-other x11 xi xext)',
+                                    '<!@(<(pkg-config) --libs-only-L --libs-only-other x11 xi xext xcb)',
                                 ],
                                 'libraries': [
-                                    '<!@(<(pkg-config) --libs-only-l x11 xi xext) -ldl',
+                                    '<!@(<(pkg-config) --libs-only-l x11 xi xext xcb) -ldl',
                                 ],
                             },
                         }],
@@ -1086,6 +1100,23 @@
                     [
                         '<@(libangle_vulkan_sources)',
                     ],
+                    'conditions':
+                    [
+                        ['OS=="win"',
+                        {
+                            'sources':
+                            [
+                                '<@(libangle_vulkan_win32_sources)',
+                            ],
+                        }],
+                        ['OS=="linux"',
+                        {
+                            'sources':
+                            [
+                                '<@(libangle_vulkan_xcb_sources)',
+                            ],
+                        }],
+                    ],
                     'dependencies':
                     [
                         'angle_vulkan',
diff --git a/src/vulkan_support/BUILD.gn b/src/vulkan_support/BUILD.gn
index 66342d3..7648e8e 100644
--- a/src/vulkan_support/BUILD.gn
+++ b/src/vulkan_support/BUILD.gn
@@ -162,6 +162,12 @@
       "VK_USE_PLATFORM_WIN32_KHX",
     ]
   }
+  if (is_linux) {
+    defines = [
+      "VK_USE_PLATFORM_XCB_KHR",
+      "VK_USE_PLATFORM_XCB_KHX",
+    ]
+  }
 }
 
 config("vulkan_internal_config") {
@@ -173,6 +179,13 @@
     # TODO(jmadill): Lift this once github issue is fixed.
     cflags += [ "-Wno-ignored-attributes" ]
   }
+  if (is_linux) {
+    defines += [
+      "SYSCONFDIR=\"/etc\"",
+      "FALLBACK_CONFIG_DIRS=\"/etc/xdg\"",
+      "FALLBACK_DATA_DIRS=\"/usr/local/share:/usr/share\"",
+    ]
+  }
 }
 
 # Vulkan loader
@@ -316,8 +329,8 @@
 config("glslang_internal_config") {
   if (is_clang || !is_win) {
     cflags = [
-      "-Wno-reorder",
       "-Wno-ignored-qualifiers",
+      "-Wno-reorder",
     ]
   }
 }
@@ -339,6 +352,9 @@
 
     sources += rebase_path(vulkan_gypi.glslang_win_sources, ".", "src")
   }
+  if (is_linux) {
+    sources += rebase_path(vulkan_gypi.glslang_unix_sources, ".", "src")
+  }
 }
 
 # The validation layers
@@ -401,16 +417,21 @@
 
 action("vulkan_gen_json_files") {
   script = "$third_party_dir/angle/scripts/generate_vulkan_layers_json.py"
-  sources =
-      rebase_path(vulkan_gypi.vulkan_gen_json_files_sources_win, ".", "src")
+  if (is_win) {
+    sources =
+        rebase_path(vulkan_gypi.vulkan_gen_json_files_sources_win, ".", "src")
+    args = [ "$raw_vulkan_layers_dir/layers/windows" ]
+  }
+  if (is_linux) {
+    sources =
+        rebase_path(vulkan_gypi.vulkan_gen_json_files_sources_linux, ".", "src")
+    args = [ "$raw_vulkan_layers_dir/layers/linux" ]
+  }
 
   # The layer JSON files are part of the necessary data deps.
   outputs = vulkan_gen_json_files_outputs
   data = vulkan_gen_json_files_outputs
-  args = [
-    "$raw_vulkan_layers_dir/layers/windows",
-    rebase_path("$root_out_dir/$data_dir"),
-  ]
+  args += [ rebase_path("$root_out_dir/$data_dir") ]
 }
 
 source_set("vulkan_layer_utils") {
diff --git a/src/vulkan_support/vulkan.gypi b/src/vulkan_support/vulkan.gypi
index dff1513..fcc2a2f 100644
--- a/src/vulkan_support/vulkan.gypi
+++ b/src/vulkan_support/vulkan.gypi
@@ -295,6 +295,15 @@
             '<(vulkan_layers_path)/layers/windows/VkLayer_threading.json',
             '<(vulkan_layers_path)/layers/windows/VkLayer_unique_objects.json',
         ],
+        'vulkan_gen_json_files_sources_linux':
+        [
+            '<(vulkan_layers_path)/layers/linux/VkLayer_core_validation.json',
+            '<(vulkan_layers_path)/layers/linux/VkLayer_object_tracker.json',
+            '<(vulkan_layers_path)/layers/linux/VkLayer_parameter_validation.json',
+            '<(vulkan_layers_path)/layers/linux/VkLayer_swapchain.json',
+            '<(vulkan_layers_path)/layers/linux/VkLayer_threading.json',
+            '<(vulkan_layers_path)/layers/linux/VkLayer_unique_objects.json',
+        ],
         'vulkan_gen_json_files_outputs':
         [
             '<(PRODUCT_DIR)/<(vulkan_json)/VkLayer_core_validation.json',
@@ -358,6 +367,13 @@
                                 '<@(glslang_win_sources)',
                             ],
                         }],
+                        ['OS=="linux"',
+                        {
+                            'sources':
+                            [
+                                '<@(glslang_unix_sources)',
+                            ],
+                        }],
                     ],
                 },
 
@@ -521,6 +537,14 @@
                                 'VK_USE_PLATFORM_WIN32_KHX',
                             ],
                         }],
+                        ['OS=="linux"',
+                        {
+                            'defines':
+                            [
+                                'VK_USE_PLATFORM_XCB_KHR',
+                                'VK_USE_PLATFORM_XCB_KHX',
+                            ],
+                        }],
                     ],
                     'direct_dependent_settings':
                     {
@@ -582,6 +606,14 @@
                                     },
                                 },
                             }],
+                            ['OS=="linux"',
+                            {
+                                'defines':
+                                [
+                                    'VK_USE_PLATFORM_XCB_KHR',
+                                    'VK_USE_PLATFORM_XCB_KHX',
+                                ],
+                            }],
                         ],
                     },
 
@@ -821,6 +853,18 @@
                                         '<(vulkan_layers_path)/layers/windows', '<(PRODUCT_DIR)/<(vulkan_json)',
                                     ],
                                 }],
+                                ['OS=="linux"',
+                                {
+                                    'inputs':
+                                    [
+                                        '<@(vulkan_gen_json_files_sources_linux)',
+                                    ],
+                                    'action':
+                                    [
+                                        'python', '<(angle_path)/scripts/generate_vulkan_layers_json.py',
+                                        '<(vulkan_layers_path)/layers/linux', '<(PRODUCT_DIR)/<(vulkan_json)',
+                                    ],
+                                }],
                             ],
                         },
                     ],
@@ -889,6 +933,14 @@
                                     'VK_USE_PLATFORM_WIN32_KHX',
                                 ],
                             }],
+                            ['OS=="linux"',
+                            {
+                                'defines':
+                                [
+                                    'VK_USE_PLATFORM_XCB_KHR',
+                                    'VK_USE_PLATFORM_XCB_KHX',
+                                ],
+                            }],
                         ],
                     },
                     'conditions':
@@ -906,6 +958,16 @@
                                 'VK_USE_PLATFORM_WIN32_KHX',
                             ],
                         }],
+                        ['OS=="linux"',
+                        {
+                            'defines':
+                            [
+                                'DEFAULT_VK_LAYERS_PATH="."',
+                                'LAYERS_SOURCE_PATH="<(vulkan_json)"',
+                                'VK_USE_PLATFORM_XCB_KHR',
+                                'VK_USE_PLATFORM_XCB_KHX',
+                            ],
+                        }],
                     ],
                     'actions':
                     [