From 65c47424e2dd558d2c79ef5f1b9008fe38b3b0bf Mon Sep 17 00:00:00 2001
From: Brendan King <Brendan.King@imgtec.com>
Date: Thu, 18 Mar 2021 13:44:57 +0000
Subject: [PATCH] pvr/wsi: add PowerVR Vulkan WSI library

PowerVR Vulkan will load the WSI library, libpvr_mesa_wsi.so,
and lookup the symbol pvr_mesa_wsi_sym_addr, which is a used to
lookup all other symbols required by Vulkan from the library.
The function is used by Vulkan to lookup the library initialisation
function, pvr_mesa_wsi_init. That function is passed the address
of another lookup function, pvr_vk_mesa_wsi_sym_addr, which is used
by the WSI library to lookup symbols in Vulkan.

The interface between PVR Vulkan and the WSI library is defined in
pvr_mesa_wsi_interface.h. Most of the functions defined on the WSI
side are wrappers around Mesa WSI functions.

---
 meson.build                          |   1 +
 meson_options.txt                    |   2 +-
 src/meson.build                      |   3 +
 src/pvr/meson.build                  |  23 ++
 src/pvr/wsi/meson.build              |  75 ++++++
 src/pvr/wsi/pvr_mesa_wsi_interface.h | 306 ++++++++++++++++++++++++
 src/pvr/wsi/pvr_wsi.c                | 333 +++++++++++++++++++++++++++
 src/pvr/wsi/pvr_wsi.h                |  78 +++++++
 src/pvr/wsi/pvr_wsi_display.c        | 293 +++++++++++++++++++++++
 src/pvr/wsi/pvr_wsi_wayland.c        |  45 ++++
 src/pvr/wsi/pvr_wsi_x11.c            |  62 +++++
 11 files changed, 1220 insertions(+), 1 deletion(-)
 create mode 100644 src/pvr/meson.build
 create mode 100644 src/pvr/wsi/meson.build
 create mode 100644 src/pvr/wsi/pvr_mesa_wsi_interface.h
 create mode 100644 src/pvr/wsi/pvr_wsi.c
 create mode 100644 src/pvr/wsi/pvr_wsi.h
 create mode 100644 src/pvr/wsi/pvr_wsi_display.c
 create mode 100644 src/pvr/wsi/pvr_wsi_wayland.c
 create mode 100644 src/pvr/wsi/pvr_wsi_x11.c

diff --git a/meson.build b/meson.build
index c0b6264..3f6ddb6 100644
--- a/meson.build
+++ b/meson.build
@@ -296,6 +296,7 @@ with_swrast_vk = _vulkan_drivers.contains('swrast')
 with_virtio_vk = _vulkan_drivers.contains('virtio-experimental')
 with_freedreno_kgsl = get_option('freedreno-kgsl')
 with_broadcom_vk = _vulkan_drivers.contains('broadcom')
+with_pvr_vk = _vulkan_drivers.contains('pvr')
 with_any_vk = _vulkan_drivers.length() != 0
 
 with_any_broadcom = with_gallium_vc4 or with_gallium_v3d or with_broadcom_vk
diff --git a/meson_options.txt b/meson_options.txt
index d36e714..e0c25a5 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -194,7 +194,7 @@ option(
   'vulkan-drivers',
   type : 'array',
   value : ['auto'],
-  choices : ['auto', 'amd', 'broadcom', 'freedreno', 'intel', 'panfrost', 'swrast', 'virtio-experimental'],
+  choices : ['auto', 'amd', 'broadcom', 'freedreno', 'intel', 'panfrost', 'swrast', 'virtio-experimental', 'pvr'],
   description : 'List of vulkan drivers to build. If this is set to auto all drivers applicable to the target OS/architecture will be built'
 )
 option(
diff --git a/src/meson.build b/src/meson.build
index f6eede5..36fec26 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -90,6 +90,9 @@ endif
 if with_gallium_panfrost or with_gallium_lima or with_panfrost_vk
   subdir('panfrost')
 endif
+if with_pvr_vk
+  subdir('pvr')
+endif
 if with_gallium_virgl or with_virtio_vk
   subdir('virtio')
 endif
diff --git a/src/pvr/meson.build b/src/pvr/meson.build
new file mode 100644
index 0000000..09a6986
--- /dev/null
+++ b/src/pvr/meson.build
@@ -0,0 +1,23 @@
+# Copyright (c) Imagination Technologies Ltd.
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+if with_pvr_vk
+  subdir('wsi')
+endif
diff --git a/src/pvr/wsi/meson.build b/src/pvr/wsi/meson.build
new file mode 100644
index 0000000..57c7623
--- /dev/null
+++ b/src/pvr/wsi/meson.build
@@ -0,0 +1,75 @@
+# Copyright (c) Imagination Technologies Ltd.
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+pvr_wsi_args = vulkan_wsi_args
+
+pvr_wsi_depends = [ dep_libdrm, idep_vulkan_util, idep_xmlconfig ]
+
+pvr_wsi_includes = [
+  inc_include,
+  inc_src,
+  inc_vulkan_util,
+  inc_vulkan_wsi
+]
+
+pvr_wsi_src = [ 'pvr_wsi.c' ]
+
+if with_platform_wayland
+  pvr_wsi_args += '-DVK_USE_PLATFORM_WAYLAND_KHR'
+
+  pvr_wsi_depends += dep_wayland_client
+
+  pvr_wsi_src += 'pvr_wsi_wayland.c'
+endif
+
+if with_platform_x11
+  pvr_wsi_args += [
+    '-DVK_USE_PLATFORM_XCB_KHR',
+    '-DVK_USE_PLATFORM_XLIB_KHR',
+  ]
+
+  pvr_wsi_depends += dep_xcb_dri2
+
+  pvr_wsi_src += 'pvr_wsi_x11.c'
+endif
+
+if system_has_kms_drm and not with_platform_android
+  pvr_wsi_args += '-DVK_USE_PLATFORM_DISPLAY_KHR'
+
+  pvr_wsi_src += 'pvr_wsi_display.c'
+endif
+
+if with_xlib_lease
+  pvr_wsi_args += '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT'
+
+  pvr_wsi_depends += dep_xlib_xrandr
+endif
+
+libvulkan_wsi = shared_library(
+  'pvr_mesa_wsi',
+  pvr_wsi_src,
+  include_directories : pvr_wsi_includes,
+  dependencies : pvr_wsi_depends,
+  c_args : pvr_wsi_args,
+  link_with: libvulkan_wsi,
+  gnu_symbol_visibility : 'hidden',
+  build_by_default : true,
+  install : true
+)
diff --git a/src/pvr/wsi/pvr_mesa_wsi_interface.h b/src/pvr/wsi/pvr_mesa_wsi_interface.h
new file mode 100644
index 0000000..b4b1bcb
--- /dev/null
+++ b/src/pvr/wsi/pvr_mesa_wsi_interface.h
@@ -0,0 +1,306 @@
+/*************************************************************************/ /*!
+@File
+@Title          PVR interface to the Vulkan WSI layer in Mesa
+@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License        MIT
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/ /**************************************************************************/
+
+#ifndef PVR_MESA_WSI_INTERFACE_H
+#define PVR_MESA_WSI_INTERFACE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <vulkan/vulkan.h>
+
+/*
+ * The pvr_mesa_wsi structure holds the Mesa WSI state, and is opaque to
+ * the PowerVK DDK.
+ */
+struct pvr_mesa_wsi;
+
+/*
+ * Functions defined in Mesa for use by the PowerVR DDK.
+ * All functions have a "pvr_mesa_wsi" prefix.
+ */
+
+void *
+pvr_mesa_wsi_sym_addr(struct pvr_mesa_wsi *mwsi,
+                      const char *name);
+
+VkResult
+pvr_mesa_wsi_init(struct pvr_mesa_wsi **mwsi,
+                  VkPhysicalDevice physicalDevice,
+                  PFN_vkVoidFunction (VKAPI_PTR *pvr_vk_mesa_wsi_sym_addr)
+                     (VkPhysicalDevice physicalDevice, const char *),
+                  const VkAllocationCallbacks *alloc,
+                  int fd,
+                  bool sw);
+
+void
+pvr_mesa_wsi_finish(struct pvr_mesa_wsi *mwsi,
+                    const VkAllocationCallbacks *alloc);
+
+VkResult
+pvr_mesa_wsi_common_get_surface_support(struct pvr_mesa_wsi *mwsi,
+                                        uint32_t queueFamilyIndex,
+                                        VkSurfaceKHR surface,
+                                        VkBool32 *pSupported);
+
+VkResult
+pvr_mesa_wsi_common_get_surface_capabilities(struct pvr_mesa_wsi *mwsi,
+                                             VkSurfaceKHR surface,
+                                             VkSurfaceCapabilitiesKHR *pSurfaceCapabilities);
+
+VkResult
+pvr_mesa_wsi_common_get_surface_capabilities2(struct pvr_mesa_wsi *mwsi,
+                                              const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
+                                              VkSurfaceCapabilities2KHR *pSurfaceCapabilities);
+
+VkResult
+pvr_mesa_wsi_common_get_surface_capabilities2ext(struct pvr_mesa_wsi *mwsi,
+                                                 VkSurfaceKHR surface,
+                                                 VkSurfaceCapabilities2EXT *pSurfaceCapabilities);
+
+VkResult
+pvr_mesa_wsi_common_get_surface_formats(struct pvr_mesa_wsi *mwsi,
+                                        VkSurfaceKHR surface,
+                                        uint32_t *pSurfaceFormatCount,
+                                        VkSurfaceFormatKHR *pSurfaceFormats);
+
+VkResult
+pvr_mesa_wsi_common_get_surface_formats2(struct pvr_mesa_wsi *mwsi,
+                                         const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
+                                         uint32_t *pSurfaceFormatCount,
+                                         VkSurfaceFormat2KHR *pSurfaceFormats);
+
+VkResult
+pvr_mesa_wsi_common_get_surface_present_modes(struct pvr_mesa_wsi *mwsi,
+                                              VkSurfaceKHR surface,
+                                              uint32_t *pPresentModeCount,
+                                              VkPresentModeKHR *pPresentModes);
+
+VkResult
+pvr_mesa_wsi_common_create_swapchain(struct pvr_mesa_wsi *mwsi,
+                                     VkDevice device,
+                                     const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                     const VkAllocationCallbacks *pAllocator,
+                                     VkSwapchainKHR *pSwapchain);
+void
+pvr_mesa_wsi_common_destroy_swapchain(struct pvr_mesa_wsi *mwsi,
+                                      VkDevice device,
+                                      VkSwapchainKHR swapchain,
+                                      const VkAllocationCallbacks *pAllocator);
+
+VkResult
+pvr_mesa_wsi_common_get_images(struct pvr_mesa_wsi *mwsi,
+                               VkSwapchainKHR swapchain,
+                               uint32_t *pSwapchainImageCount,
+                               VkImage *pSwapchainImages);
+
+VkResult
+pvr_mesa_wsi_common_acquire_next_image2(struct pvr_mesa_wsi *mwsi,
+                                        VkDevice device,
+                                        const VkAcquireNextImageInfoKHR *pAcquireInfo,
+                                        uint32_t *pImageIndex);
+
+VkResult
+pvr_mesa_wsi_common_queue_present(struct pvr_mesa_wsi *mwsi,
+                                  VkDevice device,
+                                  VkQueue queue,
+                                  int queue_family_index,
+                                  const VkPresentInfoKHR *pPresentInfo);
+
+VkResult
+pvr_mesa_wsi_common_get_present_rectangles(struct pvr_mesa_wsi *mwsi,
+                                           VkSurfaceKHR surface,
+                                           uint32_t* pRectCount,
+                                           VkRect2D* pRects);
+
+#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
+VkBool32
+pvr_mesa_wsi_get_physical_device_wayland_presentation_support(struct pvr_mesa_wsi *mwsi,
+                                                              uint32_t queueFamilyIndex,
+                                                              void *display);
+
+VkResult
+pvr_mesa_wsi_create_wayland_surface(struct pvr_mesa_wsi *mwsi,
+                                    const VkAllocationCallbacks *pAllocator,
+                                    const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
+                                    VkSurfaceKHR *pSurface);
+#endif
+
+#if defined(VK_USE_PLATFORM_XCB_KHR)
+VkBool32
+pvr_mesa_wsi_get_physical_device_xcb_presentation_support(struct pvr_mesa_wsi *mwsi,
+                                                          uint32_t queueFamilyIndex,
+                                                          void *connection,
+                                                          uint32_t visualId);
+VkResult
+pvr_mesa_wsi_create_xcb_surface(struct pvr_mesa_wsi *mwsi,
+                                const VkAllocationCallbacks *pAllocator,
+                                const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
+                                VkSurfaceKHR *pSurface);
+#endif
+
+#if defined(VK_USE_PLATFORM_XLIB_KHR)
+VkResult
+pvr_mesa_wsi_create_xlib_surface(struct pvr_mesa_wsi *mwsi,
+                                 const VkAllocationCallbacks *pAllocator,
+                                 const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
+                                 VkSurfaceKHR *pSurface);
+#endif
+
+VkResult
+pvr_mesa_wsi_display_get_physical_device_display_properties(struct pvr_mesa_wsi *mwsi,
+							    VkPhysicalDevice physicalDevice,
+							    uint32_t *pPropertyCount,
+							    VkDisplayPropertiesKHR *pProperties);
+
+VkResult
+pvr_mesa_wsi_display_get_physical_device_display_properties2(struct pvr_mesa_wsi *mwsi,
+							     VkPhysicalDevice physicalDevice,
+							     uint32_t *pPropertyCount,
+							     VkDisplayProperties2KHR *pProperties);
+
+VkResult
+pvr_mesa_wsi_display_get_physical_device_display_plane_properties(struct pvr_mesa_wsi *mwsi,
+								  VkPhysicalDevice physicalDevice,
+								  uint32_t *pPropertyCount,
+								  VkDisplayPlanePropertiesKHR *pProperties);
+
+VkResult
+pvr_mesa_wsi_display_get_physical_device_display_plane_properties2(struct pvr_mesa_wsi *mwsi,
+								   VkPhysicalDevice physicalDevice,
+								   uint32_t *pPropertyCount,
+								   VkDisplayPlaneProperties2KHR *pProperties);
+
+VkResult
+pvr_mesa_wsi_display_get_display_plane_supported_displays(struct pvr_mesa_wsi *mwsi,
+							  VkPhysicalDevice physicalDevice,
+							  uint32_t planeIndex,
+							  uint32_t *pDisplayCount,
+							  VkDisplayKHR *pDisplays);
+
+VkResult
+pvr_mesa_wsi_display_get_display_mode_properties(struct pvr_mesa_wsi *mwsi,
+						 VkPhysicalDevice physicalDevice,
+						 VkDisplayKHR display,
+						 uint32_t *pPropertyCount,
+						 VkDisplayModePropertiesKHR *pProperties);
+
+VkResult
+pvr_mesa_wsi_display_get_display_mode_properties2(struct pvr_mesa_wsi *mwsi,
+                                                  VkPhysicalDevice physicalDevice,
+                                                  VkDisplayKHR display,
+                                                  uint32_t *pPropertyCount,
+                                                  VkDisplayModeProperties2KHR *pProperties);
+
+VkResult
+pvr_mesa_wsi_display_create_display_mode(struct pvr_mesa_wsi *mwsi,
+                                         VkPhysicalDevice physicalDevice,
+                                         VkDisplayKHR display,
+                                         const VkDisplayModeCreateInfoKHR *pCreateInfo,
+                                         const VkAllocationCallbacks *pAllocator,
+                                         VkDisplayModeKHR *pMode);
+
+VkResult
+pvr_mesa_wsi_get_display_plane_capabilities(struct pvr_mesa_wsi *mwsi,
+                                            VkPhysicalDevice physicalDevice,
+                                            VkDisplayModeKHR modeKhr,
+                                            uint32_t planeIndex,
+                                            VkDisplayPlaneCapabilitiesKHR *pCapabilities);
+
+VkResult
+pvr_mesa_wsi_get_display_plane_capabilities2(struct pvr_mesa_wsi *mwsi,
+                                             VkPhysicalDevice physicalDevice,
+                                             const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
+                                             VkDisplayPlaneCapabilities2KHR *pCapabilities);
+
+VkResult
+pvr_mesa_wsi_create_display_surface(struct pvr_mesa_wsi *mwsi,
+                                    VkInstance instance,
+                                    const VkAllocationCallbacks *pAllocator,
+                                    const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
+                                    VkSurfaceKHR *pSurface);
+
+VkResult
+pvr_mesa_wsi_release_display(struct pvr_mesa_wsi *mwsi,
+                             VkPhysicalDevice physicalDevice,
+                             VkDisplayKHR display);
+
+#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT)
+VkResult
+pvr_mesa_wsi_acquire_xlib_display(struct pvr_mesa_wsi *mwsi,
+                                  VkPhysicalDevice physicalDevice,
+                                  void *dpy,
+                                  VkDisplayKHR display);
+
+VkResult
+pvr_mesa_wsi_get_randr_output_display(struct pvr_mesa_wsi *mwsi,
+                                      VkPhysicalDevice  physicalDevice,
+                                      void *dpy,
+                                      uint32_t output,
+                                      VkDisplayKHR *pDisplay);
+
+#endif
+
+VkResult
+pvr_mesa_wsi_display_power_control(struct pvr_mesa_wsi *mwsi,
+                                   VkDevice device,
+                                   VkDisplayKHR display,
+                                   const VkDisplayPowerInfoEXT *pDisplayPowerInfo);
+
+VkResult
+pvr_mesa_wsi_register_device_event(struct pvr_mesa_wsi *mwsi,
+                                   VkDevice device,
+                                   const VkDeviceEventInfoEXT *pDeviceEventInfo,
+                                   const VkAllocationCallbacks *pAllocator,
+                                   void **pFence,
+                                   int syncFd);
+
+VkResult
+pvr_mesa_wsi_register_display_event(struct pvr_mesa_wsi *mwsi,
+                                    VkDevice device,
+                                    VkDisplayKHR display,
+                                    const VkDisplayEventInfoEXT *pDisplayEventInfo,
+                                    const VkAllocationCallbacks  *pAllocator,
+                                    void **pFence,
+                                    int syncFd);
+
+VkResult
+pvr_mesa_wsi_get_swapchain_counter(struct pvr_mesa_wsi *mwsi,
+                                   VkDevice device,
+                                   VkSwapchainKHR swapchain,
+                                   VkSurfaceCounterFlagBitsEXT flagBits,
+                                   uint64_t *pValue);
+
+/*
+ * Functions defined in the PowerVR DDK for use by Mesa.
+ * All functions have a "pvr_vk_mesa_wsi" prefix.
+ */
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
+pvr_vk_mesa_wsi_sym_addr(VkPhysicalDevice physicalDevice,
+                         const char *name);
+
+#endif /* PVR_MESA_WSI_INTERFACE_H */
diff --git a/src/pvr/wsi/pvr_wsi.c b/src/pvr/wsi/pvr_wsi.c
new file mode 100644
index 0000000..a1fcdfd
--- /dev/null
+++ b/src/pvr/wsi/pvr_wsi.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright © Imagination Technologies Ltd.
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "pvr_wsi.h"
+#include "pvr_mesa_wsi_interface.h"
+
+VkResult
+pvr_mesa_wsi_init(struct pvr_mesa_wsi **pmwsi,
+                  VkPhysicalDevice physicalDevice,
+                  PFN_vkVoidFunction (VKAPI_PTR *pvr_vk_mesa_wsi_sym_addr)
+                     (VkPhysicalDevice physicalDevice, const char *),
+                  const VkAllocationCallbacks *alloc,
+                  int fd,
+                  bool sw)
+{
+   struct pvr_mesa_wsi *mwsi;
+   VkResult result;
+
+   mwsi = vk_zalloc(alloc, sizeof(*mwsi), 8,
+                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+   if (!mwsi)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   mwsi->symtab.pvr_vk_mesa_wsi_sym_addr = pvr_vk_mesa_wsi_sym_addr;
+   mwsi->physicalDevice = physicalDevice;
+
+   result = wsi_device_init(&mwsi->wsi,
+                            physicalDevice,
+                            pvr_vk_mesa_wsi_sym_addr,
+                            alloc,
+                            fd, NULL, sw);
+   if (result != VK_SUCCESS) {
+      vk_free(alloc, mwsi);
+      return result;
+   }
+
+   if (!sw)
+      mwsi->wsi.supports_modifiers = true;
+
+   *pmwsi = mwsi;
+
+   return VK_SUCCESS;
+}
+
+void
+pvr_mesa_wsi_finish(struct pvr_mesa_wsi *mwsi,
+		    const VkAllocationCallbacks *alloc)
+{
+   wsi_device_finish(&mwsi->wsi, alloc);
+
+   vk_free(alloc, mwsi);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_surface_support(struct pvr_mesa_wsi *mwsi,
+                                        uint32_t queueFamilyIndex,
+                                        VkSurfaceKHR surface,
+                                        VkBool32 *pSupported)
+{
+   return wsi_common_get_surface_support(&mwsi->wsi,
+                                         queueFamilyIndex,
+                                         surface,
+                                         pSupported);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_surface_capabilities(struct pvr_mesa_wsi *mwsi,
+                                             VkSurfaceKHR surface,
+                                             VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
+{
+   return wsi_common_get_surface_capabilities(&mwsi->wsi,
+                                              surface,
+                                              pSurfaceCapabilities);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_surface_capabilities2(struct pvr_mesa_wsi *mwsi,
+                                              const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
+                                              VkSurfaceCapabilities2KHR *pSurfaceCapabilities)
+{
+   return wsi_common_get_surface_capabilities2(&mwsi->wsi,
+                                               pSurfaceInfo,
+                                               pSurfaceCapabilities);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_surface_capabilities2ext(struct pvr_mesa_wsi *mwsi,
+                                                 VkSurfaceKHR surface,
+                                                 VkSurfaceCapabilities2EXT *pSurfaceCapabilities)
+{
+   return wsi_common_get_surface_capabilities2ext(&mwsi->wsi,
+                                                  surface,
+                                                  pSurfaceCapabilities);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_surface_formats(struct pvr_mesa_wsi *mwsi,
+                                        VkSurfaceKHR surface,
+                                        uint32_t *pSurfaceFormatCount,
+                                        VkSurfaceFormatKHR *pSurfaceFormats)
+{
+   return wsi_common_get_surface_formats(&mwsi->wsi,
+                                         surface,
+                                         pSurfaceFormatCount,
+                                         pSurfaceFormats);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_surface_formats2(struct pvr_mesa_wsi *mwsi,
+                                         const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
+                                         uint32_t *pSurfaceFormatCount,
+                                         VkSurfaceFormat2KHR *pSurfaceFormats)
+{
+   return wsi_common_get_surface_formats2(&mwsi->wsi,
+                                          pSurfaceInfo,
+                                          pSurfaceFormatCount,
+                                          pSurfaceFormats);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_surface_present_modes(struct pvr_mesa_wsi *mwsi,
+                                              VkSurfaceKHR surface,
+                                              uint32_t *pPresentModeCount,
+                                              VkPresentModeKHR *pPresentModes)
+{
+   return wsi_common_get_surface_present_modes(&mwsi->wsi,
+                                               surface,
+                                               pPresentModeCount,
+                                               pPresentModes);
+}
+
+VkResult
+pvr_mesa_wsi_common_create_swapchain(struct pvr_mesa_wsi *mwsi,
+                                     VkDevice device,
+                                     const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                     const VkAllocationCallbacks *pAllocator,
+                                     VkSwapchainKHR *pSwapchain)
+{
+   return wsi_common_create_swapchain(&mwsi->wsi,
+                                      device,
+                                      pCreateInfo,
+                                      pAllocator,
+                                      pSwapchain);
+}
+
+void
+pvr_mesa_wsi_common_destroy_swapchain(UNUSED struct pvr_mesa_wsi *mwsi,
+                                      VkDevice device,
+                                      VkSwapchainKHR swapchain,
+                                      const VkAllocationCallbacks *pAllocator)
+{
+   return wsi_common_destroy_swapchain(device,
+                                       swapchain,
+                                       pAllocator);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_images(UNUSED struct pvr_mesa_wsi *mwsi,
+                               VkSwapchainKHR swapchain,
+                               uint32_t *pSwapchainImageCount,
+                               VkImage *pSwapchainImages)
+{
+   return wsi_common_get_images(swapchain,
+                                pSwapchainImageCount,
+                                pSwapchainImages);
+}
+
+VkResult
+pvr_mesa_wsi_common_acquire_next_image2(struct pvr_mesa_wsi *mwsi,
+                                        VkDevice device,
+                                        const VkAcquireNextImageInfoKHR *pAcquireInfo,
+                                        uint32_t *pImageIndex)
+{
+   return wsi_common_acquire_next_image2(&mwsi->wsi,
+                                         device,
+                                         pAcquireInfo,
+                                         pImageIndex);
+}
+
+VkResult
+pvr_mesa_wsi_common_queue_present(struct pvr_mesa_wsi *mwsi,
+                                  VkDevice device,
+                                  VkQueue queue,
+                                  int queue_family_index,
+                                  const VkPresentInfoKHR *pPresentInfo)
+{
+   return wsi_common_queue_present(&mwsi->wsi,
+                                   device,
+                                   queue,
+                                   queue_family_index,
+                                   pPresentInfo);
+}
+
+VkResult
+pvr_mesa_wsi_common_get_present_rectangles(struct pvr_mesa_wsi *mwsi,
+                                           VkSurfaceKHR surface,
+                                           uint32_t* pRectCount,
+                                           VkRect2D* pRects)
+{
+   return wsi_common_get_present_rectangles(&mwsi->wsi,
+                                            surface,
+                                            pRectCount,
+                                            pRects);
+}
+
+/*
+ * The mwsi parameter is currently unused. Note that it is invalid for
+ * pvr_mesa_wsi_init, which is responsible for allocating it.
+*/
+PUBLIC void *
+pvr_mesa_wsi_sym_addr(UNUSED struct pvr_mesa_wsi *mwsi, const char *name)
+{
+   static const struct {
+      char *name;
+      void *addr;
+   } lookup[] = {
+      { "pvr_mesa_wsi_init",
+            pvr_mesa_wsi_init },
+      { "pvr_mesa_wsi_finish",
+            pvr_mesa_wsi_finish },
+      { "pvr_mesa_wsi_common_get_surface_support",
+            pvr_mesa_wsi_common_get_surface_support },
+      { "pvr_mesa_wsi_common_get_surface_capabilities",
+            pvr_mesa_wsi_common_get_surface_capabilities },
+      { "pvr_mesa_wsi_common_get_surface_capabilities2",
+            pvr_mesa_wsi_common_get_surface_capabilities2 },
+      { "pvr_mesa_wsi_common_get_surface_capabilities2ext",
+            pvr_mesa_wsi_common_get_surface_capabilities2ext },
+      { "pvr_mesa_wsi_common_get_surface_formats",
+            pvr_mesa_wsi_common_get_surface_formats },
+      { "pvr_mesa_wsi_common_get_surface_formats2",
+            pvr_mesa_wsi_common_get_surface_formats2 },
+      { "pvr_mesa_wsi_common_get_surface_present_modes",
+            pvr_mesa_wsi_common_get_surface_present_modes },
+      { "pvr_mesa_wsi_common_create_swapchain",
+            pvr_mesa_wsi_common_create_swapchain },
+      { "pvr_mesa_wsi_common_destroy_swapchain",
+            pvr_mesa_wsi_common_destroy_swapchain },
+      { "pvr_mesa_wsi_common_get_images",
+            pvr_mesa_wsi_common_get_images },
+      { "pvr_mesa_wsi_common_acquire_next_image2",
+            pvr_mesa_wsi_common_acquire_next_image2 },
+      { "pvr_mesa_wsi_common_queue_present",
+            pvr_mesa_wsi_common_queue_present },
+      { "pvr_mesa_wsi_common_get_present_rectangles",
+            pvr_mesa_wsi_common_get_present_rectangles },
+#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
+      { "pvr_mesa_wsi_get_physical_device_wayland_presentation_support",
+            pvr_mesa_wsi_get_physical_device_wayland_presentation_support },
+      { "pvr_mesa_wsi_create_wayland_surface",
+            pvr_mesa_wsi_create_wayland_surface },
+#endif
+#if defined(VK_USE_PLATFORM_XCB_KHR)
+      { "pvr_mesa_wsi_get_physical_device_xcb_presentation_support",
+            pvr_mesa_wsi_get_physical_device_xcb_presentation_support },
+      { "pvr_mesa_wsi_create_xcb_surface",
+            pvr_mesa_wsi_create_xcb_surface },
+#endif
+#if defined(VK_USE_PLATFORM_XLIB_KHR)
+      { "pvr_mesa_wsi_create_xlib_surface",
+            pvr_mesa_wsi_create_xlib_surface },
+#endif
+      { "pvr_mesa_wsi_display_get_physical_device_display_properties",
+            pvr_mesa_wsi_display_get_physical_device_display_properties },
+      { "pvr_mesa_wsi_display_get_physical_device_display_properties2",
+            pvr_mesa_wsi_display_get_physical_device_display_properties2 },
+      { "pvr_mesa_wsi_display_get_physical_device_display_plane_properties",
+            pvr_mesa_wsi_display_get_physical_device_display_plane_properties },
+      { "pvr_mesa_wsi_display_get_physical_device_display_plane_properties2",
+            pvr_mesa_wsi_display_get_physical_device_display_plane_properties2 },
+      { "pvr_mesa_wsi_display_get_display_plane_supported_displays",
+            pvr_mesa_wsi_display_get_display_plane_supported_displays },
+      { "pvr_mesa_wsi_display_get_display_mode_properties",
+            pvr_mesa_wsi_display_get_display_mode_properties },
+      { "pvr_mesa_wsi_display_get_display_mode_properties2",
+            pvr_mesa_wsi_display_get_display_mode_properties2 },
+      { "pvr_mesa_wsi_display_create_display_mode",
+            pvr_mesa_wsi_display_create_display_mode },
+      { "pvr_mesa_wsi_get_display_plane_capabilities",
+            pvr_mesa_wsi_get_display_plane_capabilities },
+      { "pvr_mesa_wsi_get_display_plane_capabilities2",
+            pvr_mesa_wsi_get_display_plane_capabilities2 },
+      { "pvr_mesa_wsi_create_display_surface",
+            pvr_mesa_wsi_create_display_surface },
+      { "pvr_mesa_wsi_release_display",
+            pvr_mesa_wsi_release_display },
+#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT)
+      { "pvr_mesa_wsi_acquire_xlib_display",
+            pvr_mesa_wsi_acquire_xlib_display },
+      { "pvr_mesa_wsi_get_randr_output_display",
+            pvr_mesa_wsi_get_randr_output_display },
+#endif
+      { "pvr_mesa_wsi_display_power_control",
+            pvr_mesa_wsi_display_power_control },
+      { "pvr_mesa_wsi_register_device_event",
+            pvr_mesa_wsi_register_device_event },
+      { "pvr_mesa_wsi_register_display_event",
+            pvr_mesa_wsi_register_display_event },
+      { "pvr_mesa_wsi_get_swapchain_counter",
+            pvr_mesa_wsi_get_swapchain_counter },
+   };
+   unsigned i;
+
+   for (i = 0; i < ARRAY_SIZE(lookup); i++) {
+      if (!strcmp(name, lookup[i].name))
+         return lookup[i].addr;
+   }
+
+   return NULL;
+}
diff --git a/src/pvr/wsi/pvr_wsi.h b/src/pvr/wsi/pvr_wsi.h
new file mode 100644
index 0000000..142358d
--- /dev/null
+++ b/src/pvr/wsi/pvr_wsi.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright © Imagination Technologies Ltd.
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#if !defined PVR_WSI_H
+#define PVR_WSI_H
+
+#include "util/macros.h"
+#include "util/u_memory.h"
+#include "util/u_atomic.h"
+
+#include "wsi_common.h"
+
+#define  Container(p, s, m) ((s *) ((uintptr_t)(p) - Offset(s, m)))
+
+#define _MAKE_STRING(x) # x
+#define MAKE_STRING(x) _MAKE_STRING(x)
+
+#define LOOKUP_DDK(mwsi, sym) \
+   mwsi->symtab.pvr_vk_mesa_wsi_sym_addr(MAKE_STRING(sym))
+
+#define JUMP_DDK(mwsi, sym, ...)                          \
+   do {                                                   \
+      void *_entry = p_atomic_read(&mwsi->symtab.sym);    \
+                                                          \
+      if (!_entry) {                                      \
+         _entry = LOOKUP_DDK(mwsi, sym);                  \
+                                                          \
+         if (_entry)                                      \
+            p_atomic_set(&mwsi->symtab.sym, _entry);      \
+      }                                                   \
+                                                          \
+      if (_entry) {                                       \
+         __typeof__(mwsi->symtab.sym) _func = _entry;     \
+                                                          \
+         return _func(__VA_ARGS__);                       \
+      }                                                   \
+   } while(0)
+
+struct pvr_vk_mesa_wsi_sym_tab
+{
+   PFN_vkVoidFunction (VKAPI_PTR *pvr_vk_mesa_wsi_sym_addr)
+      (VkPhysicalDevice physicalDevice, const char *);
+};
+
+struct pvr_mesa_wsi
+{
+   struct wsi_device wsi;
+   struct pvr_vk_mesa_wsi_sym_tab symtab;
+   VkPhysicalDevice physicalDevice;
+};
+
+static inline struct pvr_mesa_wsi *pvr_mesa_wsi(struct wsi_device *wsi_ptr)
+{
+   return Container(wsi_ptr, struct pvr_mesa_wsi, wsi);
+}
+
+#endif
diff --git a/src/pvr/wsi/pvr_wsi_display.c b/src/pvr/wsi/pvr_wsi_display.c
new file mode 100644
index 0000000..65a1c99
--- /dev/null
+++ b/src/pvr/wsi/pvr_wsi_display.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright © Imagination Technologies Ltd.
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wsi_common_display.h"
+
+#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT)
+#include "wsi_common_x11.h"
+#endif
+
+#include "pvr_wsi.h"
+#include "pvr_mesa_wsi_interface.h"
+
+VkResult
+pvr_mesa_wsi_display_get_physical_device_display_properties(struct pvr_mesa_wsi *mwsi,
+							    VkPhysicalDevice physicalDevice,
+							    uint32_t *pPropertyCount,
+							    VkDisplayPropertiesKHR *pProperties)
+{
+   return wsi_display_get_physical_device_display_properties(physicalDevice,
+                                                             &mwsi->wsi,
+                                                             pPropertyCount,
+                                                             pProperties);
+}
+
+VkResult
+pvr_mesa_wsi_display_get_physical_device_display_properties2(struct pvr_mesa_wsi *mwsi,
+							     VkPhysicalDevice physicalDevice,
+							     uint32_t *pPropertyCount,
+							     VkDisplayProperties2KHR *pProperties)
+{
+   return wsi_display_get_physical_device_display_properties2(physicalDevice,
+                                                              &mwsi->wsi,
+                                                              pPropertyCount,
+                                                              pProperties);
+}
+
+VkResult
+pvr_mesa_wsi_display_get_physical_device_display_plane_properties(struct pvr_mesa_wsi *mwsi,
+								  VkPhysicalDevice physicalDevice,
+								  uint32_t *pPropertyCount,
+								  VkDisplayPlanePropertiesKHR *pProperties)
+{
+   return wsi_display_get_physical_device_display_plane_properties(physicalDevice,
+                                                                   &mwsi->wsi,
+                                                                   pPropertyCount,
+                                                                   pProperties);
+}
+
+VkResult
+pvr_mesa_wsi_display_get_physical_device_display_plane_properties2(struct pvr_mesa_wsi *mwsi,
+								   VkPhysicalDevice physicalDevice,
+								   uint32_t *pPropertyCount,
+								   VkDisplayPlaneProperties2KHR *pProperties)
+{
+   return wsi_display_get_physical_device_display_plane_properties2(physicalDevice,
+                                                                    &mwsi->wsi,
+                                                                    pPropertyCount,
+                                                                    pProperties);
+}
+
+VkResult
+pvr_mesa_wsi_display_get_display_plane_supported_displays(struct pvr_mesa_wsi *mwsi,
+							  VkPhysicalDevice physicalDevice,
+							  uint32_t planeIndex,
+							  uint32_t *pDisplayCount,
+							  VkDisplayKHR *pDisplays)
+{
+   return wsi_display_get_display_plane_supported_displays(physicalDevice,
+                                                           &mwsi->wsi,
+                                                           planeIndex,
+                                                           pDisplayCount,
+                                                           pDisplays);
+
+}
+
+VkResult
+pvr_mesa_wsi_display_get_display_mode_properties(struct pvr_mesa_wsi *mwsi,
+						 VkPhysicalDevice physicalDevice,
+						 VkDisplayKHR display,
+						 uint32_t *pPropertyCount,
+						 VkDisplayModePropertiesKHR *pProperties)
+{
+   return wsi_display_get_display_mode_properties(physicalDevice,
+                                                  &mwsi->wsi,
+                                                  display,
+                                                  pPropertyCount,
+                                                  pProperties);
+}
+
+VkResult
+pvr_mesa_wsi_display_get_display_mode_properties2(struct pvr_mesa_wsi *mwsi,
+                                                  VkPhysicalDevice physicalDevice,
+                                                  VkDisplayKHR display,
+                                                  uint32_t *pPropertyCount,
+                                                  VkDisplayModeProperties2KHR *pProperties)
+{
+   return wsi_display_get_display_mode_properties2(physicalDevice,
+                                                   &mwsi->wsi,
+                                                   display,
+                                                   pPropertyCount,
+                                                   pProperties);
+}
+
+VkResult
+pvr_mesa_wsi_display_create_display_mode(struct pvr_mesa_wsi *mwsi,
+                                         VkPhysicalDevice physicalDevice,
+                                         VkDisplayKHR display,
+                                         const VkDisplayModeCreateInfoKHR *pCreateInfo,
+                                         const VkAllocationCallbacks *pAllocator,
+                                         VkDisplayModeKHR *pMode)
+{
+   return wsi_display_create_display_mode(physicalDevice,
+                                          &mwsi->wsi,
+                                          display,
+                                          pCreateInfo,
+                                          pAllocator,
+                                          pMode);
+}
+
+VkResult
+pvr_mesa_wsi_get_display_plane_capabilities(struct pvr_mesa_wsi *mwsi,
+                                            VkPhysicalDevice physicalDevice,
+                                            VkDisplayModeKHR modeKhr,
+                                            uint32_t planeIndex,
+                                            VkDisplayPlaneCapabilitiesKHR *pCapabilities)
+{
+   return wsi_get_display_plane_capabilities(physicalDevice,
+                                             &mwsi->wsi,
+                                             modeKhr,
+                                             planeIndex,
+                                             pCapabilities);
+}
+
+VkResult
+pvr_mesa_wsi_get_display_plane_capabilities2(struct pvr_mesa_wsi *mwsi,
+                                             VkPhysicalDevice physicalDevice,
+                                             const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
+                                             VkDisplayPlaneCapabilities2KHR *pCapabilities)
+{
+   return wsi_get_display_plane_capabilities2(physicalDevice,
+                                              &mwsi->wsi,
+                                              pDisplayPlaneInfo,
+                                              pCapabilities);
+}
+
+VkResult
+pvr_mesa_wsi_create_display_surface(UNUSED struct pvr_mesa_wsi *mwsi,
+                                    VkInstance instance,
+                                    const VkAllocationCallbacks *pAllocator,
+                                    const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
+                                    VkSurfaceKHR *pSurface)
+{
+   return wsi_create_display_surface(instance,
+                                      pAllocator,
+                                      pCreateInfo,
+                                      pSurface);
+}
+
+VkResult
+pvr_mesa_wsi_release_display(struct pvr_mesa_wsi *mwsi,
+                             VkPhysicalDevice physicalDevice,
+                             VkDisplayKHR display)
+{
+   return wsi_release_display(physicalDevice,
+                              &mwsi->wsi,
+                              display);
+}
+
+#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT)
+VkResult
+pvr_mesa_wsi_acquire_xlib_display(struct pvr_mesa_wsi *mwsi,
+                                  VkPhysicalDevice physicalDevice,
+                                  void *dpy,
+                                  VkDisplayKHR display)
+{
+   return wsi_acquire_xlib_display(physicalDevice,
+                                   &mwsi->wsi,
+                                   dpy,
+                                   display);
+}
+
+VkResult
+pvr_mesa_wsi_get_randr_output_display(struct pvr_mesa_wsi *mwsi,
+                                      VkPhysicalDevice  physicalDevice,
+                                      void *dpy,
+                                      uint32_t output,
+                                      VkDisplayKHR *pDisplay)
+{
+   return wsi_get_randr_output_display(physicalDevice,
+                                       &mwsi->wsi,
+                                       dpy,
+                                       output,
+                                       pDisplay);
+}
+#endif
+
+VkResult
+pvr_mesa_wsi_display_power_control(struct pvr_mesa_wsi *mwsi,
+                                   VkDevice device,
+                                   VkDisplayKHR display,
+                                   const VkDisplayPowerInfoEXT *pDisplayPowerInfo)
+{
+   return wsi_display_power_control(device,
+                                    &mwsi->wsi,
+                                    display,
+                                    pDisplayPowerInfo);
+}
+
+VkResult
+pvr_mesa_wsi_register_device_event(struct pvr_mesa_wsi *mwsi,
+                                   VkDevice device,
+                                   const VkDeviceEventInfoEXT *pDeviceEventInfo,
+                                   const VkAllocationCallbacks *pAllocator,
+                                   void **pFence,
+                                   int syncFd)
+{
+   struct wsi_fence *fence;
+   VkResult ret;
+
+   ret = wsi_register_device_event(device,
+                                   &mwsi->wsi,
+                                   pDeviceEventInfo,
+                                   pAllocator,
+                                   pFence ? &fence : NULL,
+                                   syncFd);
+
+   if (ret == VK_SUCCESS && pFence != NULL)
+	   *pFence = fence;
+
+   return ret;
+}
+
+VkResult
+pvr_mesa_wsi_register_display_event(struct pvr_mesa_wsi *mwsi,
+                                    VkDevice device,
+                                    VkDisplayKHR display,
+                                    const VkDisplayEventInfoEXT *pDisplayEventInfo,
+                                    const VkAllocationCallbacks  *pAllocator,
+                                    void **pFence,
+                                    int syncFd)
+{
+   struct wsi_fence *fence;
+   VkResult ret;
+
+   ret = wsi_register_display_event(device,
+                                    &mwsi->wsi,
+                                    display,
+                                    pDisplayEventInfo,
+                                    pAllocator,
+                                    pFence ? &fence : NULL,
+                                    syncFd);
+
+   if (ret == VK_SUCCESS && pFence != NULL)
+	   *pFence = fence;
+
+   return ret;
+}
+
+VkResult
+pvr_mesa_wsi_get_swapchain_counter(struct pvr_mesa_wsi *mwsi,
+                                   VkDevice device,
+                                   VkSwapchainKHR swapchain,
+                                   VkSurfaceCounterFlagBitsEXT flagBits,
+                                   uint64_t *pValue)
+{
+   return wsi_get_swapchain_counter(device,
+                                    &mwsi->wsi,
+                                    swapchain,
+                                    flagBits,
+                                    pValue);
+}
+
diff --git a/src/pvr/wsi/pvr_wsi_wayland.c b/src/pvr/wsi/pvr_wsi_wayland.c
new file mode 100644
index 0000000..5b05266
--- /dev/null
+++ b/src/pvr/wsi/pvr_wsi_wayland.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright © Imagination Technologies Ltd.
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wsi_common_wayland.h"
+
+#include "pvr_wsi.h"
+#include "pvr_mesa_wsi_interface.h"
+
+VkBool32
+pvr_mesa_wsi_get_physical_device_wayland_presentation_support(struct pvr_mesa_wsi *mwsi,
+                                                              uint32_t queueFamilyIndex,
+                                                              void *display)
+{
+   return wsi_wl_get_presentation_support(&mwsi->wsi, display);
+}
+
+VkResult
+pvr_mesa_wsi_create_wayland_surface(UNUSED struct pvr_mesa_wsi *mwsi,
+                                    const VkAllocationCallbacks *pAllocator,
+                                    const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
+                                    VkSurfaceKHR *pSurface)
+{
+   return wsi_create_wl_surface(pAllocator, pCreateInfo, pSurface);
+}
diff --git a/src/pvr/wsi/pvr_wsi_x11.c b/src/pvr/wsi/pvr_wsi_x11.c
new file mode 100644
index 0000000..0a69e92
--- /dev/null
+++ b/src/pvr/wsi/pvr_wsi_x11.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright © Imagination Technologies Ltd.
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wsi_common_x11.h"
+
+#include "pvr_wsi.h"
+#include "pvr_mesa_wsi_interface.h"
+
+VkBool32
+pvr_mesa_wsi_get_physical_device_xcb_presentation_support(struct pvr_mesa_wsi *mwsi,
+                                                          uint32_t queueFamilyIndex,
+                                                          void *connection,
+                                                          uint32_t visual_id)
+{
+   return wsi_get_physical_device_xcb_presentation_support(&mwsi->wsi,
+                                                           queueFamilyIndex,
+                                                           connection,
+                                                           visual_id);
+}
+
+VkResult
+pvr_mesa_wsi_create_xcb_surface(UNUSED struct pvr_mesa_wsi *mwsi,
+                                const VkAllocationCallbacks *pAllocator,
+                                const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
+                                VkSurfaceKHR *pSurface)
+{
+   return wsi_create_xcb_surface(pAllocator,
+				 pCreateInfo,
+				 pSurface);
+}
+
+VkResult
+pvr_mesa_wsi_create_xlib_surface(UNUSED struct pvr_mesa_wsi *mwsi,
+                                 const VkAllocationCallbacks *pAllocator,
+                                 const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
+                                 VkSurfaceKHR *pSurface)
+{
+   return wsi_create_xlib_surface(pAllocator,
+				  pCreateInfo,
+				  pSurface);
+}
