vk: Add WSI implementation
authorKristian Høgsberg <kristian.h.kristensen@intel.com>
Sat, 16 May 2015 05:04:52 +0000 (22:04 -0700)
committerKristian Høgsberg <kristian.h.kristensen@intel.com>
Thu, 21 May 2015 03:34:52 +0000 (20:34 -0700)
include/vulkan/vk_wsi_lunarg.h [new file with mode: 0644]
src/vulkan/Makefile.am
src/vulkan/device.c
src/vulkan/image.c
src/vulkan/private.h
src/vulkan/x11.c [new file with mode: 0644]

diff --git a/include/vulkan/vk_wsi_lunarg.h b/include/vulkan/vk_wsi_lunarg.h
new file mode 100644 (file)
index 0000000..84de8d2
--- /dev/null
@@ -0,0 +1,197 @@
+//
+// File: vk_wsi_display.h
+//
+/*
+** Copyright (c) 2014 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are 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 Materials.
+**
+** THE MATERIALS ARE 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
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#ifndef __VK_WSI_LUNARG_H__
+#define __VK_WSI_LUNARG_H__
+
+#include "vulkan.h"
+
+#define VK_WSI_LUNARG_REVISION             3
+#define VK_WSI_LUNARG_EXTENSION_NUMBER     1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+// ------------------------------------------------------------------------------------------------
+// Objects
+
+VK_DEFINE_DISP_SUBCLASS_HANDLE(VkDisplayWSI, VkObject)
+VK_DEFINE_DISP_SUBCLASS_HANDLE(VkSwapChainWSI, VkObject)
+
+// ------------------------------------------------------------------------------------------------
+// Enumeration constants
+
+#define VK_WSI_LUNARG_ENUM(type,id)    ((type)(VK_WSI_LUNARG_EXTENSION_NUMBER * -1000 + (id)))
+
+// Extend VkPhysicalDeviceInfoType enum with extension specific constants
+#define VK_PHYSICAL_DEVICE_INFO_TYPE_DISPLAY_PROPERTIES_WSI         VK_WSI_LUNARG_ENUM(VkPhysicalDeviceInfoType, 0)
+#define VK_PHYSICAL_DEVICE_INFO_TYPE_QUEUE_PRESENT_PROPERTIES_WSI   VK_WSI_LUNARG_ENUM(VkPhysicalDeviceInfoType, 1)
+
+// Extend VkStructureType enum with extension specific constants
+#define VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI                VK_WSI_LUNARG_ENUM(VkStructureType, 0)
+#define VK_STRUCTURE_TYPE_PRESENT_INFO_WSI                          VK_WSI_LUNARG_ENUM(VkStructureType, 1)
+
+// Extend VkImageLayout enum with extension specific constants
+#define VK_IMAGE_LAYOUT_PRESENT_SOURCE_WSI                          VK_WSI_LUNARG_ENUM(VkImageLayout, 0)
+
+// Extend VkObjectType enum for new objects
+#define VK_OBJECT_TYPE_DISPLAY_WSI                                  VK_WSI_LUNARG_ENUM(VkObjectType, 0)
+#define VK_OBJECT_TYPE_SWAP_CHAIN_WSI                               VK_WSI_LUNARG_ENUM(VkObjectType, 1)
+
+// ------------------------------------------------------------------------------------------------
+// Enumerations
+
+typedef enum VkDisplayInfoTypeWSI_
+{
+    // Info type for vkGetDisplayInfo()
+    VK_DISPLAY_INFO_TYPE_FORMAT_PROPERTIES_WSI              = 0x00000003,   // Return the VkFormat(s) supported for swap chains with the display
+
+    VK_ENUM_RANGE(DISPLAY_INFO_TYPE, FORMAT_PROPERTIES_WSI, FORMAT_PROPERTIES_WSI)
+} VkDisplayInfoTypeWSI;
+
+typedef enum VkSwapChainInfoTypeWSI_
+{
+    // Info type for vkGetSwapChainInfo()
+    VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI           = 0x00000000,   // Return information about the persistent images of the swapchain
+
+    VK_ENUM_RANGE(SWAP_CHAIN_INFO_TYPE, PERSISTENT_IMAGES_WSI, PERSISTENT_IMAGES_WSI)
+} VkSwapChainInfoTypeWSI;
+
+// ------------------------------------------------------------------------------------------------
+// Flags
+
+typedef VkFlags VkSwapModeFlagsWSI;
+typedef enum VkSwapModeFlagBitsWSI_
+{
+    VK_SWAP_MODE_FLIP_BIT_WSI                               = VK_BIT(0),
+    VK_SWAP_MODE_BLIT_BIT_WSI                               = VK_BIT(1),
+} VkSwapModeFlagBitsWSI;
+
+// ------------------------------------------------------------------------------------------------
+// Structures
+
+typedef struct VkDisplayPropertiesWSI_
+{
+    VkDisplayWSI                            display;            // Handle of the display object
+    VkExtent2D                              physicalResolution; // Max resolution for CRT?
+} VkDisplayPropertiesWSI;
+
+typedef struct VkDisplayFormatPropertiesWSI_
+{
+    VkFormat                                swapChainFormat;    // Format of the images of the swap chain
+} VkDisplayFormatPropertiesWSI;
+
+typedef struct VkSwapChainCreateInfoWSI_
+{
+    VkStructureType                         sType;              // Must be VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI
+    const void*                             pNext;              // Pointer to next structure
+
+    // TBD: It is not yet clear what the use will be for the following two
+    // values.  It seems to be needed for more-global window-system handles
+    // (e.g. X11 display).  If not needed for the SDK, we will drop it from
+    // this extension, and from a future version of this header.
+    const void*                             pNativeWindowSystemHandle; // Pointer to native window system handle
+    const void*                             pNativeWindowHandle; // Pointer to native window handle
+
+    uint32_t                                displayCount;       // Number of displays the swap chain is created for
+    const VkDisplayWSI*                     pDisplays;          // displayCount number of display objects the swap chain is created for
+
+    uint32_t                                imageCount;         // Number of images in the swap chain
+
+    VkFormat                                imageFormat;        // Format of the images of the swap chain
+    VkExtent2D                              imageExtent;        // Width and height of the images of the swap chain
+    uint32_t                                imageArraySize;     // Number of layers of the images of the swap chain (needed for multi-view rendering)
+    VkFlags                                 imageUsageFlags;    // Usage flags for the images of the swap chain (see VkImageUsageFlags)
+
+    VkFlags                                 swapModeFlags;      // Allowed swap modes (see VkSwapModeFlagsWSI)
+} VkSwapChainCreateInfoWSI;
+
+typedef struct VkSwapChainImageInfoWSI_
+{
+    VkImage                                 image;              // Persistent swap chain image handle
+    VkDeviceMemory                          memory;             // Persistent swap chain image's memory handle
+} VkSwapChainImageInfoWSI;
+
+typedef struct VkPhysicalDeviceQueuePresentPropertiesWSI_
+{
+    bool32_t                                supportsPresent;    // Tells whether the queue supports presenting
+} VkPhysicalDeviceQueuePresentPropertiesWSI;
+
+typedef struct VkPresentInfoWSI_
+{
+    VkStructureType                         sType;              // Must be VK_STRUCTURE_TYPE_PRESENT_INFO_WSI
+    const void*                             pNext;              // Pointer to next structure
+    VkImage                                 image;              // Image to present
+    uint32_t                                flipInterval;       // Flip interval
+} VkPresentInfoWSI;
+
+// ------------------------------------------------------------------------------------------------
+// Function types
+
+typedef VkResult (VKAPI *PFN_vkGetDisplayInfoWSI)(VkDisplayWSI display, VkDisplayInfoTypeWSI infoType, size_t* pDataSize, void* pData);
+typedef VkResult (VKAPI *PFN_vkCreateSwapChainWSI)(VkDevice device, const VkSwapChainCreateInfoWSI* pCreateInfo, VkSwapChainWSI* pSwapChain);
+typedef VkResult (VKAPI *PFN_vkDestroySwapChainWSI)(VkSwapChainWSI swapChain);
+typedef VkResult (VKAPI *PFN_vkGetSwapChainInfoWSI)(VkSwapChainWSI swapChain, VkSwapChainInfoTypeWSI infoType, size_t* pDataSize, void* pData);
+typedef VkResult (VKAPI *PFN_vkQueuePresentWSI)(VkQueue queue, const VkPresentInfoWSI* pPresentInfo);
+
+// ------------------------------------------------------------------------------------------------
+// Function prototypes
+
+#ifdef VK_PROTOTYPES
+
+VkResult VKAPI vkGetDisplayInfoWSI(
+    VkDisplayWSI                            display,
+    VkDisplayInfoTypeWSI                    infoType,
+    size_t*                                 pDataSize,
+    void*                                   pData);
+
+VkResult VKAPI vkCreateSwapChainWSI(
+    VkDevice                                device,
+    const VkSwapChainCreateInfoWSI*         pCreateInfo,
+    VkSwapChainWSI*                         pSwapChain);
+
+VkResult VKAPI vkDestroySwapChainWSI(
+    VkSwapChainWSI                          swapChain);
+
+VkResult VKAPI vkGetSwapChainInfoWSI(
+    VkSwapChainWSI                          swapChain,
+    VkSwapChainInfoTypeWSI                  infoType,
+    size_t*                                 pDataSize,
+    void*                                   pData);
+
+VkResult VKAPI vkQueuePresentWSI(
+    VkQueue                                 queue,
+    const VkPresentInfoWSI*                 pPresentInfo);
+
+#endif // VK_PROTOTYPES
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif // __VK_WSI_LUNARG_H__
index 8c05c5139fc4312863f3ab881742e899d698e91d..404af61bcb1271e5faf19c08b00297139d86956e 100644 (file)
 
 vulkan_includedir = $(includedir)/vulkan
 
-vulkan_include_HEADERS = \
-       $(top_srcdir)/include/vulkan/vk_platform.h \
-       $(top_srcdir)/include/vulkan/vulkan.h \
-       $(top_srcdir)/include/vulkan/vulkan_intel.h
+vulkan_include_HEADERS =                               \
+       $(top_srcdir)/include/vulkan/vk_platform.h      \
+       $(top_srcdir)/include/vulkan/vulkan.h           \
+       $(top_srcdir)/include/vulkan/vulkan_intel.h     \
+       $(top_srcdir)/include/vulkan/vk_wsi_lunarg.h
 
 lib_LTLIBRARIES = libvulkan.la
 
@@ -64,6 +65,7 @@ libvulkan_la_SOURCES =                                \
        intel.c                                 \
        entrypoints.c                           \
        entrypoints.h                           \
+       x11.c                                   \
        formats.c                               \
        compiler.cpp
 
index cad85bf5ec326f1b15bfb4b70d42dda2cba3ac4d..7cce0a1a394dca209b0ea5816fe1c4c0070e79b1 100644 (file)
@@ -187,9 +187,10 @@ VkResult anv_GetPhysicalDeviceInfo(
    VkPhysicalDevicePerformance *performance;
    VkPhysicalDeviceQueueProperties *queue_properties;
    VkPhysicalDeviceMemoryProperties *memory_properties;
+   VkDisplayPropertiesWSI *display_properties;
    uint64_t ns_per_tick = 80;
    
-   switch (infoType) {
+   switch ((uint32_t) infoType) {
    case VK_PHYSICAL_DEVICE_INFO_TYPE_PROPERTIES:
       properties = pData;
 
@@ -252,6 +253,23 @@ VkResult anv_GetPhysicalDeviceInfo(
       memory_properties->supportsPinning = false;
       return VK_SUCCESS;
 
+   case VK_PHYSICAL_DEVICE_INFO_TYPE_DISPLAY_PROPERTIES_WSI:
+      anv_finishme("VK_PHYSICAL_DEVICE_INFO_TYPE_DISPLAY_PROPERTIES_WSI");
+
+      *pDataSize = sizeof(*display_properties);
+      if (pData == NULL)
+         return VK_SUCCESS;
+
+      display_properties = pData;
+      display_properties->display = 0;
+      display_properties->physicalResolution = (VkExtent2D) { 0, 0 };
+      return VK_SUCCESS;
+
+   case VK_PHYSICAL_DEVICE_INFO_TYPE_QUEUE_PRESENT_PROPERTIES_WSI:
+      anv_finishme("VK_PHYSICAL_DEVICE_INFO_TYPE_QUEUE_PRESENT_PROPERTIES_WSI");
+      return VK_SUCCESS;
+
+
    default:
       return VK_UNSUPPORTED;
    }
@@ -383,18 +401,28 @@ VkResult anv_GetGlobalExtensionInfo(
     size_t*                                     pDataSize,
     void*                                       pData)
 {
-   uint32_t *count;
+   static const VkExtensionProperties extensions[] = {
+      {
+         .extName = "VK_WSI_LunarG",
+         .version = 3
+      }
+   };
+   uint32_t count = ARRAY_SIZE(extensions);
 
    switch (infoType) {
    case VK_EXTENSION_INFO_TYPE_COUNT:
-      count = pData;
-      assert(*pDataSize == 4);
-      *count = 0;
+      memcpy(pData, &count, sizeof(count));
+      *pDataSize = sizeof(count);
       return VK_SUCCESS;
-      
+
    case VK_EXTENSION_INFO_TYPE_PROPERTIES:
-      return vk_error(VK_ERROR_INVALID_EXTENSION);
-      
+      if (extensionIndex >= count)
+         return vk_error(VK_ERROR_INVALID_EXTENSION);
+
+      memcpy(pData, &extensions[extensionIndex], sizeof(extensions[0]));
+      *pDataSize = sizeof(extensions[0]);
+      return VK_SUCCESS;
+
    default:
       return VK_UNSUPPORTED;
    }
index cf658e969da05962fc92e4ba7aabd063e6c3f115..a7dc243b2a2c3419a61cc273fed585d1c1c56b67 100644 (file)
@@ -41,9 +41,10 @@ static const struct anv_tile_mode_info {
    [WMAJOR] = { 128, 32 }
 };
 
-VkResult anv_CreateImage(
+VkResult anv_image_create(
     VkDevice                                    _device,
     const VkImageCreateInfo*                    pCreateInfo,
+    const struct anv_image_create_info *        extra,
     VkImage*                                    pImage)
 {
    struct anv_device *device = (struct anv_device *) _device;
@@ -63,6 +64,7 @@ VkResult anv_CreateImage(
    image->type = pCreateInfo->imageType;
    image->format = pCreateInfo->format;
    image->extent = pCreateInfo->extent;
+   image->swap_chain = NULL;
 
    assert(image->extent.width > 0);
    assert(image->extent.height > 0);
@@ -71,20 +73,28 @@ VkResult anv_CreateImage(
    switch (pCreateInfo->tiling) {
    case VK_IMAGE_TILING_LINEAR:
       image->tile_mode = LINEAR;
-      /* Linear depth buffers must be 64 byte aligned, which is the strictest
-       * requirement for all kinds of linear surfaces.
-       */
-      image->alignment = 64;
       break;
    case VK_IMAGE_TILING_OPTIMAL:
       image->tile_mode = YMAJOR;
-      image->alignment = 4096;
       break;
    default:
       break;
    }
    
+   if (extra)
+      image->tile_mode = extra->tile_mode;
+
+   if (image->tile_mode == LINEAR) {
+      /* Linear depth buffers must be 64 byte aligned, which is the strictest
+       * requirement for all kinds of linear surfaces.
+       */
+      image->alignment = 64;
+   } else {
+      image->alignment = 4096;
+   }
+
    format = anv_format_for_vk_format(pCreateInfo->format);
+   assert(format->cpp > 0);
    image->stride = ALIGN_I32(image->extent.width * format->cpp,
                              tile_mode_info[image->tile_mode].tile_width);
    aligned_height = ALIGN_I32(image->extent.height,
@@ -96,6 +106,14 @@ VkResult anv_CreateImage(
    return VK_SUCCESS;
 }
 
+VkResult anv_CreateImage(
+    VkDevice                                    device,
+    const VkImageCreateInfo*                    pCreateInfo,
+    VkImage*                                    pImage)
+{
+   return anv_image_create(device, pCreateInfo, NULL, pImage);
+}
+
 VkResult anv_GetImageSubresourceInfo(
     VkDevice                                    device,
     VkImage                                     image,
index e4534f26e8c67c0f4b2d87b4f66238da0d5bf970..f15856387d8b0225fc0dcd63a1405e29e013362a 100644 (file)
@@ -36,6 +36,7 @@
 #define VK_PROTOTYPES
 #include <vulkan/vulkan.h>
 #include <vulkan/vulkan_intel.h>
+#include <vulkan/vk_wsi_lunarg.h>
 
 #include "entrypoints.h"
 
@@ -661,6 +662,8 @@ struct anv_image {
    /* Set when bound */
    struct anv_bo *                              bo;
    VkDeviceSize                                 offset;
+
+   struct anv_swap_chain *                      swap_chain;
 };
 
 struct anv_surface_view {
@@ -671,6 +674,15 @@ struct anv_surface_view {
    VkFormat                                     format;
 };
 
+struct anv_image_create_info {
+   uint32_t                                     tile_mode;
+};
+
+VkResult anv_image_create(VkDevice _device,
+                          const VkImageCreateInfo *pCreateInfo,
+                          const struct anv_image_create_info *extra,
+                          VkImage *pImage);
+
 void anv_image_view_init(struct anv_surface_view *view,
                          struct anv_device *device,
                          const VkImageViewCreateInfo* pCreateInfo,
diff --git a/src/vulkan/x11.c b/src/vulkan/x11.c
new file mode 100644 (file)
index 0000000..898aba0
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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 "private.h"
+
+#include <xcb/xcb.h>
+#include <xcb/dri3.h>
+#include <xcb/present.h>
+
+static const VkFormat formats[] = {
+   VK_FORMAT_B5G6R5_UNORM,
+   VK_FORMAT_B8G8R8A8_UNORM,
+   VK_FORMAT_B8G8R8A8_SRGB,
+};
+
+VkResult anv_GetDisplayInfoWSI(
+    VkDisplayWSI                            display,
+    VkDisplayInfoTypeWSI                    infoType,
+    size_t*                                 pDataSize,
+    void*                                   pData)
+{
+   VkDisplayFormatPropertiesWSI *properties = pData;
+   size_t size;
+
+   if (pDataSize == NULL)
+      return VK_ERROR_INVALID_POINTER;
+
+   switch (infoType) {
+   case VK_DISPLAY_INFO_TYPE_FORMAT_PROPERTIES_WSI:
+      size = sizeof(properties[0]) * ARRAY_SIZE(formats);
+      if (pData && *pDataSize < size)
+         return vk_error(VK_ERROR_INVALID_VALUE);
+
+      *pDataSize = size;
+      for (uint32_t i = 0; i < ARRAY_SIZE(formats); i++)
+         properties[i].swapChainFormat = formats[i];
+
+      return VK_SUCCESS;
+
+   default:
+      return VK_UNSUPPORTED;
+   }
+}
+
+struct anv_swap_chain {
+   struct anv_device *                          device;
+   xcb_connection_t *                           conn;
+   xcb_window_t                                 window;
+   xcb_gc_t                                     gc;
+   VkExtent2D                                   extent;
+   uint32_t                                     count;
+   struct {
+      struct anv_image *                        image;
+      struct anv_device_memory *                memory;
+      xcb_pixmap_t                              pixmap;
+   }                                            images[0];
+};
+
+VkResult anv_CreateSwapChainWSI(
+    VkDevice                                _device,
+    const VkSwapChainCreateInfoWSI*         pCreateInfo,
+    VkSwapChainWSI*                         pSwapChain)
+{
+   struct anv_device *device = (struct anv_device *) _device;
+   struct anv_swap_chain *chain;
+   xcb_void_cookie_t cookie;
+   VkResult result;
+   size_t size;
+   int ret;
+
+   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI);
+
+   size = sizeof(*chain) + pCreateInfo->imageCount * sizeof(chain->images[0]);
+   chain = anv_device_alloc(device, size, 8,
+                            VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+   if (chain == NULL)
+      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   chain->device = device;
+   chain->conn = (xcb_connection_t *) pCreateInfo->pNativeWindowSystemHandle;
+   chain->window = (xcb_window_t) (uintptr_t) pCreateInfo->pNativeWindowHandle;
+   chain->count = pCreateInfo->imageCount;
+   chain->extent = pCreateInfo->imageExtent;
+
+   for (uint32_t i = 0; i < chain->count; i++) {
+      struct anv_image *image;
+      struct anv_device_memory *memory;
+
+      anv_image_create((VkDevice) device,
+                       &(VkImageCreateInfo) {
+                          .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+                          .imageType = VK_IMAGE_TYPE_2D,
+                          .format = pCreateInfo->imageFormat,
+                          .extent = {
+                             .width = pCreateInfo->imageExtent.width,
+                             .height = pCreateInfo->imageExtent.height,
+                             .depth = 1
+                          },
+                          .mipLevels = 1,
+                          .arraySize = 1,
+                          .samples = 1,
+                          /* FIXME: Need a way to use X tiling to allow scanout */
+                          .tiling = VK_IMAGE_TILING_OPTIMAL,
+                          .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+                          .flags = 0,
+                       },
+                       &(struct anv_image_create_info) {
+                          .tile_mode = XMAJOR
+                       },
+                       (VkImage *) &image);
+
+      anv_AllocMemory((VkDevice) device,
+                      &(VkMemoryAllocInfo) {
+                         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
+                         .allocationSize = image->size,
+                      },
+                      (VkDeviceMemory *) &memory);
+
+      anv_QueueBindObjectMemory(VK_NULL_HANDLE,
+                                VK_OBJECT_TYPE_IMAGE,
+                                (VkImage) image, 0,
+                                (VkDeviceMemory) memory, 0);
+
+      ret = anv_gem_set_tiling(device, memory->bo.gem_handle,
+                               image->stride, I915_TILING_X);
+      if (ret) {
+         result = vk_error(VK_ERROR_UNKNOWN);
+         goto fail;
+      }
+
+      int fd = anv_gem_handle_to_fd(device, memory->bo.gem_handle);
+      if (fd == -1) {
+         result = vk_error(VK_ERROR_UNKNOWN);
+         goto fail;
+      }
+
+      uint32_t bpp = 32;
+      uint32_t depth = 24;
+      xcb_pixmap_t pixmap = xcb_generate_id(chain->conn);
+
+      cookie =
+         xcb_dri3_pixmap_from_buffer_checked(chain->conn,
+                                             pixmap,
+                                             chain->window,
+                                             image->size,
+                                             pCreateInfo->imageExtent.width,
+                                             pCreateInfo->imageExtent.height,
+                                             image->stride,
+                                             depth, bpp, fd);
+
+      chain->images[i].image = image;
+      chain->images[i].memory = memory;
+      chain->images[i].pixmap = pixmap;
+      image->swap_chain = chain;
+
+      xcb_discard_reply(chain->conn, cookie.sequence);
+   }
+
+   chain->gc = xcb_generate_id(chain->conn);
+   if (!chain->gc) {
+      result = vk_error(VK_ERROR_UNKNOWN);
+      goto fail;
+   }
+
+   cookie = xcb_create_gc(chain->conn,
+                          chain->gc,
+                          chain->window,
+                          XCB_GC_GRAPHICS_EXPOSURES,
+                          (uint32_t []) { 0 });
+   xcb_discard_reply(chain->conn, cookie.sequence);
+
+   *pSwapChain = (VkSwapChainWSI) chain;
+
+   return VK_SUCCESS;
+
+ fail:
+   return result;
+}
+
+VkResult anv_DestroySwapChainWSI(
+    VkSwapChainWSI                          swapChain)
+{
+   struct anv_swap_chain *chain = (struct anv_swap_chain *) swapChain;
+   struct anv_device *device = chain->device;
+
+   anv_device_free(device, chain);
+
+   return VK_SUCCESS;
+}
+
+VkResult anv_GetSwapChainInfoWSI(
+    VkSwapChainWSI                          swapChain,
+    VkSwapChainInfoTypeWSI                  infoType,
+    size_t*                                 pDataSize,
+    void*                                   pData)
+{
+   struct anv_swap_chain *chain = (struct anv_swap_chain *) swapChain;
+   VkSwapChainImageInfoWSI *images;
+   size_t size;
+
+   switch (infoType) {
+   case VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI:
+      size = sizeof(*images) * chain->count;
+      if (pData && *pDataSize < size)
+         return VK_ERROR_INVALID_VALUE;
+
+      *pDataSize = size;
+      if (!pData)
+         return VK_SUCCESS;
+
+      images = pData;
+      for (uint32_t i = 0; i < chain->count; i++) {
+         images[i].image = (VkImage) chain->images[i].image;
+         images[i].memory = (VkDeviceMemory) chain->images[i].memory;
+      }
+
+      return VK_SUCCESS;
+
+   default:
+      return VK_UNSUPPORTED;
+   }
+}
+
+VkResult anv_QueuePresentWSI(
+    VkQueue                                 queue_,
+    const VkPresentInfoWSI*                 pPresentInfo)
+{
+   struct anv_image *image = (struct anv_image *) pPresentInfo->image;
+   struct anv_swap_chain *chain = image->swap_chain;
+   xcb_void_cookie_t cookie;
+   xcb_pixmap_t pixmap;
+
+   assert(pPresentInfo->sType == VK_STRUCTURE_TYPE_PRESENT_INFO_WSI);
+
+   if (chain == NULL)
+      return vk_error(VK_ERROR_INVALID_VALUE);
+
+   pixmap = XCB_NONE;
+   for (uint32_t i = 0; i < chain->count; i++) {
+      if ((VkImage) chain->images[i].image == pPresentInfo->image) {
+         pixmap = chain->images[i].pixmap;
+         break;
+      }
+   }
+
+   if (pixmap == XCB_NONE)
+      return vk_error(VK_ERROR_INVALID_VALUE);
+
+   cookie = xcb_copy_area(chain->conn,
+                          pixmap,
+                          chain->window,
+                          chain->gc,
+                          0, 0,
+                          0, 0,
+                          chain->extent.width,
+                          chain->extent.height);
+   xcb_discard_reply(chain->conn, cookie.sequence);
+
+   xcb_flush(chain->conn);
+
+   return VK_SUCCESS;
+}