vulkan: Add skeleton swapchain support

Loader and driver entry points exist and the call chains are hooked up
properly, but functions are just empty stubs for now.

Change-Id: I6ff95e47d1d09ebed41eda8accb71686c8249546
(cherry picked from commit 038c8a740bbda4650bec776023a26a7fcbf93864)
diff --git a/vulkan/include/vulkan/vk_ext_android_native_buffer.h b/vulkan/include/vulkan/vk_ext_android_native_buffer.h
new file mode 100644
index 0000000..a1311f4
--- /dev/null
+++ b/vulkan/include/vulkan/vk_ext_android_native_buffer.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VK_EXT_ANDROID_NATIVE_BUFFER_H__
+#define __VK_EXT_ANDROID_NATIVE_BUFFER_H__
+
+#include <vulkan/vulkan.h>
+#include <system/window.h>
+
+// TODO(jessehall): Get a real extension number officially assigned.
+#define VK_EXT_ANDROID_NATIVE_BUFFER_EXTENSION_NUMBER 1024
+#define VK_EXT_ANDROID_NATIVE_BUFFER_REVISION         1
+#define VK_EXT_ANDROID_NATIVE_BUFFER_EXTENSION_NAME   "VK_EXT_ANDROID_gralloc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// See https://gitlab.khronos.org/vulkan/vulkan/blob/master/doc/proposals/proposed/NVIDIA/VulkanRegistryProposal.txt
+// and Khronos bug 14154 for explanation of these magic numbers.
+#define VK_EXT_ANDROID_NATIVE_BUFFER_ENUM(type,id)    ((type)((int)0xc0000000 - VK_EXT_ANDROID_NATIVE_BUFFER_EXTENSION_NUMBER * -1024 + (id)))
+#define VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID       VK_EXT_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 0)
+
+typedef struct {
+    VkStructureType             sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID
+    const void*                 pNext;
+
+    // Buffer handle and stride returned from gralloc alloc()
+    buffer_handle_t             handle;
+    int                         stride;
+
+    // Gralloc format and usage requested when the buffer was allocated.
+    int                         format;
+    int                         usage;
+} VkNativeBufferANDROID;
+
+typedef VkResult (VKAPI *PFN_vkImportNativeFenceANDROID)(VkDevice device, VkSemaphore semaphore, int nativeFenceFd);
+typedef VkResult (VKAPI *PFN_vkQueueSignalNativeFenceANDROID)(VkQueue queue, int* pNativeFenceFd);
+
+#ifdef VK_PROTOTYPES
+VkResult VKAPI vkImportNativeFenceANDROID(
+    VkDevice        device,
+    VkSemaphore     semaphore,
+    int             nativeFenceFd
+);
+VkResult VKAPI vkQueueSignalNativeFenceANDROID(
+    VkQueue         queue,
+    int*            pNativeFenceFd
+);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __VK_EXT_ANDROID_NATIVE_BUFFER_H__
diff --git a/vulkan/include/vulkan/vk_ext_khr_device_swapchain.h b/vulkan/include/vulkan/vk_ext_khr_device_swapchain.h
new file mode 100644
index 0000000..b254586
--- /dev/null
+++ b/vulkan/include/vulkan/vk_ext_khr_device_swapchain.h
@@ -0,0 +1,210 @@
+//
+// File: vk_ext_khr_device_swapchain.h
+//
+/*
+** Copyright (c) 2015 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_EXT_KHR_DEVICE_SWAPCHAIN_H__
+#define __VK_EXT_KHR_DEVICE_SWAPCHAIN_H__
+
+#include "vulkan.h"
+
+#define VK_EXT_KHR_DEVICE_SWAPCHAIN_REVISION         51
+#define VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NUMBER 2
+#define VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME   "VK_EXT_KHR_device_swapchain"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+// ------------------------------------------------------------------------------------------------
+// Objects
+
+VK_DEFINE_NONDISP_HANDLE(VkSwapchainKHR);
+
+// ------------------------------------------------------------------------------------------------
+// Enumeration constants
+
+#define VK_EXT_KHR_DEVICE_SWAPCHAIN_ENUM(type,id)    ((type)((int)0xc0000000 - VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NUMBER * -1024 + (id)))
+#define VK_EXT_KHR_DEVICE_SWAPCHAIN_ENUM_POSITIVE(type,id)    ((type)((int)0x40000000 + (VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NUMBER - 1) * 1024 + (id)))
+
+// Extend VkStructureType enum with extension specific constants
+#define VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_KHR VK_EXT_KHR_DEVICE_SWAPCHAIN_ENUM(VkStructureType, 0)
+#define VK_STRUCTURE_TYPE_PRESENT_INFO_KHR VK_EXT_KHR_DEVICE_SWAPCHAIN_ENUM(VkStructureType, 1)
+
+// Extend VkImageLayout enum with extension specific constants
+#define VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR VK_EXT_KHR_DEVICE_SWAPCHAIN_ENUM(VkImageLayout, 2)
+
+// Extend VkResult enum with extension specific constants
+//  Return codes for successful operation execution
+#define VK_SUBOPTIMAL_KHR           VK_EXT_KHR_DEVICE_SWAPCHAIN_ENUM_POSITIVE(VkResult, 3)
+//  Error codes
+#define VK_ERROR_OUT_OF_DATE_KHR    VK_EXT_KHR_DEVICE_SWAPCHAIN_ENUM(VkResult, 4)
+
+// ------------------------------------------------------------------------------------------------
+// Enumerations
+
+typedef enum {
+    VK_PRESENT_MODE_IMMEDIATE_KHR = 0,
+    VK_PRESENT_MODE_MAILBOX_KHR = 1,
+    VK_PRESENT_MODE_FIFO_KHR = 2,
+    VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR,
+    VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_KHR,
+    VK_PRESENT_MODE_NUM = (VK_PRESENT_MODE_FIFO_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1),
+    VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkPresentModeKHR;
+
+typedef enum {
+    VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0x00000000,
+    VK_COLORSPACE_NUM = (VK_COLORSPACE_SRGB_NONLINEAR_KHR - VK_COLORSPACE_SRGB_NONLINEAR_KHR + 1),
+    VK_COLORSPACE_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkColorSpaceKHR;
+
+// ------------------------------------------------------------------------------------------------
+// Flags
+
+// ------------------------------------------------------------------------------------------------
+// Structures
+
+typedef struct {
+    uint32_t                                minImageCount;      // Supported minimum number of images for the surface
+    uint32_t                                maxImageCount;      // Supported maximum number of images for the surface, 0 for unlimited
+
+    VkExtent2D                              currentExtent;      // Current image width and height for the surface, (-1, -1) if undefined
+    VkExtent2D                              minImageExtent;     // Supported minimum image width and height for the surface
+    VkExtent2D                              maxImageExtent;     // Supported maximum image width and height for the surface
+
+    VkSurfaceTransformFlagsKHR              supportedTransforms;// 1 or more bits representing the transforms supported
+    VkSurfaceTransformKHR                   currentTransform;   // The surface's current transform relative to the device's natural orientation
+
+    uint32_t                                maxImageArraySize;  // Supported maximum number of image layers for the surface
+
+    VkImageUsageFlags                       supportedUsageFlags;// Supported image usage flags for the surface
+} VkSurfacePropertiesKHR;
+
+typedef struct {
+    VkFormat                                format;             // Supported pair of rendering format
+    VkColorSpaceKHR                         colorSpace;         // and colorspace for the surface
+} VkSurfaceFormatKHR;
+
+typedef struct {
+    VkStructureType                          sType;             // Must be VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_KHR
+    const void*                              pNext;             // Pointer to next structure
+
+    const VkSurfaceDescriptionKHR*           pSurfaceDescription;// describes the swap chain's target surface
+
+    uint32_t                                 minImageCount;     // Minimum number of presentation images the application needs
+    VkFormat                                 imageFormat;       // Format of the presentation images
+    VkColorSpaceKHR                          imageColorSpace;   // Colorspace of the presentation images
+    VkExtent2D                               imageExtent;       // Dimensions of the presentation images
+    VkImageUsageFlags                        imageUsageFlags;   // Bits indicating how the presentation images will be used
+    VkSurfaceTransformKHR                    preTransform;      // The transform, relative to the device's natural orientation, applied to the image content prior to presentation
+    uint32_t                                 imageArraySize;    // Determines the number of views for multiview/stereo presentation
+
+    VkSharingMode                            sharingMode;       // Sharing mode used for the presentation images
+    uint32_t                                 queueFamilyCount;  // Number of queue families having access to the images in case of concurrent sharing mode
+    const uint32_t*                          pQueueFamilyIndices; // Array of queue family indices having access to the images in case of concurrent sharing mode
+
+    VkPresentModeKHR                         presentMode;       // Which presentation mode to use for presents on this swap chain
+
+    VkSwapchainKHR                           oldSwapchain;      // Existing swap chain to replace, if any
+
+    VkBool32                                 clipped;           // Specifies whether presentable images may be affected by window clip regions
+} VkSwapchainCreateInfoKHR;
+
+typedef struct {
+    VkStructureType                          sType;             // Must be VK_STRUCTURE_TYPE_PRESENT_INFO_KHR
+    const void*                              pNext;             // Pointer to next structure
+    uint32_t                                 swapchainCount;    // Number of swap chains to present in this call
+    const VkSwapchainKHR*                    swapchains;        // Swap chains to present an image from
+    const uint32_t*                          imageIndices;      // Indices of which swapchain images to present
+} VkPresentInfoKHR;
+
+// ------------------------------------------------------------------------------------------------
+// Function types
+
+typedef VkResult (VKAPI *PFN_vkGetSurfacePropertiesKHR)(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkSurfacePropertiesKHR* pSurfaceProperties);
+typedef VkResult (VKAPI *PFN_vkGetSurfaceFormatsKHR)(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkSurfaceFormatKHR* pSurfaceFormats);
+typedef VkResult (VKAPI *PFN_vkGetSurfacePresentModesKHR)(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkPresentModeKHR* pPresentModes);
+typedef VkResult (VKAPI *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain);
+typedef VkResult (VKAPI *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain);
+typedef VkResult (VKAPI *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pCount, VkImage* pSwapchainImages);
+typedef VkResult (VKAPI *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, uint32_t* pImageIndex);
+typedef VkResult (VKAPI *PFN_vkQueuePresentKHR)(VkQueue queue, VkPresentInfoKHR* pPresentInfo);
+
+// ------------------------------------------------------------------------------------------------
+// Function prototypes
+
+#ifdef VK_PROTOTYPES
+
+VkResult VKAPI vkGetSurfacePropertiesKHR(
+    VkDevice                                 device,
+    const VkSurfaceDescriptionKHR*           pSurfaceDescription,
+    VkSurfacePropertiesKHR*                  pSurfaceProperties);
+
+VkResult VKAPI vkGetSurfaceFormatsKHR(
+    VkDevice                                 device,
+    const VkSurfaceDescriptionKHR*           pSurfaceDescription,
+    uint32_t*                                pCount,
+    VkSurfaceFormatKHR*                      pSurfaceFormats);
+
+VkResult VKAPI vkGetSurfacePresentModesKHR(
+    VkDevice                                 device,
+    const VkSurfaceDescriptionKHR*           pSurfaceDescription,
+    uint32_t*                                pCount,
+    VkPresentModeKHR*                        pPresentModes);
+
+VkResult VKAPI vkCreateSwapchainKHR(
+    VkDevice                                 device,
+    const VkSwapchainCreateInfoKHR*          pCreateInfo,
+    VkSwapchainKHR*                          pSwapchain);
+
+VkResult VKAPI vkDestroySwapchainKHR(
+    VkDevice                                 device,
+    VkSwapchainKHR                           swapchain);
+
+VkResult VKAPI vkGetSwapchainImagesKHR(
+    VkDevice                                 device,
+    VkSwapchainKHR                           swapchain,
+    uint32_t*                                pCount,
+    VkImage*                                 pSwapchainImages);
+
+VkResult VKAPI vkAcquireNextImageKHR(
+    VkDevice                                 device,
+    VkSwapchainKHR                           swapchain,
+    uint64_t                                 timeout,
+    VkSemaphore                              semaphore,
+    uint32_t*                                pImageIndex);
+
+VkResult VKAPI vkQueuePresentKHR(
+    VkQueue                                  queue,
+    VkPresentInfoKHR*                        pPresentInfo);
+
+#endif // VK_PROTOTYPES
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif // __VK_EXT_KHR_SWAPCHAIN_H__
diff --git a/vulkan/include/vulkan/vk_ext_khr_swapchain.h b/vulkan/include/vulkan/vk_ext_khr_swapchain.h
new file mode 100644
index 0000000..862b4d5
--- /dev/null
+++ b/vulkan/include/vulkan/vk_ext_khr_swapchain.h
@@ -0,0 +1,153 @@
+//
+// File: vk_ext_khr_swapchain.h
+//
+/*
+** Copyright (c) 2015 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_EXT_KHR_SWAPCHAIN_H__
+#define __VK_EXT_KHR_SWAPCHAIN_H__
+
+#include "vulkan.h"
+
+#define VK_EXT_KHR_SWAPCHAIN_REVISION         17
+#define VK_EXT_KHR_SWAPCHAIN_EXTENSION_NUMBER 1
+#define VK_EXT_KHR_SWAPCHAIN_EXTENSION_NAME   "VK_EXT_KHR_swapchain"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+// ------------------------------------------------------------------------------------------------
+// Objects
+
+// ------------------------------------------------------------------------------------------------
+// Enumeration constants
+
+#define VK_EXT_KHR_SWAPCHAIN_ENUM(type,id)    ((type)((int)0xc0000000 - VK_EXT_KHR_SWAPCHAIN_EXTENSION_NUMBER * -1024 + (id)))
+#define VK_EXT_KHR_SWAPCHAIN_ENUM_POSITIVE(type,id)    ((type)((int)0x40000000 + (VK_EXT_KHR_SWAPCHAIN_EXTENSION_NUMBER - 1) * 1024 + (id)))
+
+// Extend VkStructureType enum with extension specific constants
+#define VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR            VK_EXT_KHR_SWAPCHAIN_ENUM(VkStructureType, 0)
+
+// ------------------------------------------------------------------------------------------------
+// Enumerations
+
+typedef enum {
+    VK_SURFACE_TRANSFORM_NONE_KHR = 0,
+    VK_SURFACE_TRANSFORM_ROT90_KHR = 1,
+    VK_SURFACE_TRANSFORM_ROT180_KHR = 2,
+    VK_SURFACE_TRANSFORM_ROT270_KHR = 3,
+    VK_SURFACE_TRANSFORM_HMIRROR_KHR = 4,
+    VK_SURFACE_TRANSFORM_HMIRROR_ROT90_KHR = 5,
+    VK_SURFACE_TRANSFORM_HMIRROR_ROT180_KHR = 6,
+    VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR = 7,
+    VK_SURFACE_TRANSFORM_INHERIT_KHR = 8,
+} VkSurfaceTransformKHR;
+
+typedef enum {
+    VK_SURFACE_TRANSFORM_NONE_BIT_KHR = 0x00000001,
+    VK_SURFACE_TRANSFORM_ROT90_BIT_KHR = 0x00000002,
+    VK_SURFACE_TRANSFORM_ROT180_BIT_KHR = 0x00000004,
+    VK_SURFACE_TRANSFORM_ROT270_BIT_KHR = 0x00000008,
+    VK_SURFACE_TRANSFORM_HMIRROR_BIT_KHR = 0x00000010,
+    VK_SURFACE_TRANSFORM_HMIRROR_ROT90_BIT_KHR = 0x00000020,
+    VK_SURFACE_TRANSFORM_HMIRROR_ROT180_BIT_KHR = 0x00000040,
+    VK_SURFACE_TRANSFORM_HMIRROR_ROT270_BIT_KHR = 0x00000080,
+    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100,
+} VkSurfaceTransformFlagBitsKHR;
+typedef VkFlags VkSurfaceTransformFlagsKHR;
+
+typedef enum {
+    VK_PLATFORM_WIN32_KHR = 0,
+    VK_PLATFORM_X11_KHR = 1,
+    VK_PLATFORM_XCB_KHR = 2,
+    VK_PLATFORM_ANDROID_KHR = 3,
+    VK_PLATFORM_WAYLAND_KHR = 4,
+    VK_PLATFORM_MIR_KHR = 5,
+    VK_PLATFORM_BEGIN_RANGE_KHR = VK_PLATFORM_WIN32_KHR,
+    VK_PLATFORM_END_RANGE_KHR = VK_PLATFORM_MIR_KHR,
+    VK_PLATFORM_NUM_KHR = (VK_PLATFORM_MIR_KHR - VK_PLATFORM_WIN32_KHR + 1),
+    VK_PLATFORM_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkPlatformKHR;
+
+// ------------------------------------------------------------------------------------------------
+// Flags
+
+// ------------------------------------------------------------------------------------------------
+// Structures
+
+// Placeholder structure header for the different types of surface description structures
+typedef struct {
+    VkStructureType                          sType;             // Can be any of the VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_XXX_KHR constants
+    const void*                              pNext;             // Pointer to next structure
+} VkSurfaceDescriptionKHR;
+
+// Surface description structure for a native platform window surface
+typedef struct {
+    VkStructureType                         sType;              // Must be VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR
+    const void*                             pNext;              // Pointer to next structure
+    VkPlatformKHR                           platform;           // e.g. VK_PLATFORM_*_KHR
+    void*                                   pPlatformHandle;
+    void*                                   pPlatformWindow;
+} VkSurfaceDescriptionWindowKHR;
+
+// pPlatformHandle points to this struct when platform is VK_PLATFORM_X11_KHR
+#ifdef _X11_XLIB_H_
+typedef struct {
+    Display*                                 dpy;               // Display connection to an X server
+    Window                                   root;              // To identify the X screen
+} VkPlatformHandleX11KHR;
+#endif /* _X11_XLIB_H_ */
+
+// pPlatformHandle points to this struct when platform is VK_PLATFORM_XCB_KHR
+#ifdef __XCB_H__
+typedef struct {
+    xcb_connection_t*                        connection;        // XCB connection to an X server
+    xcb_window_t                             root;              // To identify the X screen
+} VkPlatformHandleXcbKHR;
+#endif /* __XCB_H__ */
+
+// ------------------------------------------------------------------------------------------------
+// Function types
+
+typedef VkResult (VKAPI *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkBool32* pSupported);
+
+// ------------------------------------------------------------------------------------------------
+// Function prototypes
+
+#ifdef VK_PROTOTYPES
+
+VkResult VKAPI vkGetPhysicalDeviceSurfaceSupportKHR(
+    VkPhysicalDevice                        physicalDevice,
+    uint32_t                                queueFamilyIndex,
+    const VkSurfaceDescriptionKHR*          pSurfaceDescription,
+    VkBool32*                               pSupported);
+
+#endif // VK_PROTOTYPES
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif // __VK_EXT_KHR_SWAPCHAIN_H__
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index 3ba7ecd..5898678 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -30,7 +30,8 @@
 LOCAL_SRC_FILES := \
 	entry.cpp \
 	get_proc_addr.cpp \
-	loader.cpp
+	loader.cpp \
+	swapchain.cpp
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_SHARED_LIBRARIES := libhardware liblog
diff --git a/vulkan/libvulkan/entry.cpp b/vulkan/libvulkan/entry.cpp
index f2b4482..cd5dd99 100644
--- a/vulkan/libvulkan/entry.cpp
+++ b/vulkan/libvulkan/entry.cpp
@@ -800,3 +800,48 @@
 void vkCmdExecuteCommands(VkCmdBuffer cmdBuffer, uint32_t cmdBuffersCount, const VkCmdBuffer* pCmdBuffers) {
     GetVtbl(cmdBuffer).CmdExecuteCommands(cmdBuffer, cmdBuffersCount, pCmdBuffers);
 }
+
+__attribute__((visibility("default")))
+VkResult vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkBool32* pSupported) {
+    return GetVtbl(physicalDevice).GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, pSurfaceDescription, pSupported);
+}
+
+__attribute__((visibility("default")))
+VkResult vkGetSurfacePropertiesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkSurfacePropertiesKHR* pSurfaceProperties) {
+    return GetVtbl(device).GetSurfacePropertiesKHR(device, pSurfaceDescription, pSurfaceProperties);
+}
+
+__attribute__((visibility("default")))
+VkResult vkGetSurfaceFormatsKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkSurfaceFormatKHR* pSurfaceFormats) {
+    return GetVtbl(device).GetSurfaceFormatsKHR(device, pSurfaceDescription, pCount, pSurfaceFormats);
+}
+
+__attribute__((visibility("default")))
+VkResult vkGetSurfacePresentModesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkPresentModeKHR* pPresentModes) {
+    return GetVtbl(device).GetSurfacePresentModesKHR(device, pSurfaceDescription, pCount, pPresentModes);
+}
+
+__attribute__((visibility("default")))
+VkResult vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain) {
+    return GetVtbl(device).CreateSwapchainKHR(device, pCreateInfo, pSwapchain);
+}
+
+__attribute__((visibility("default")))
+VkResult vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain) {
+    return GetVtbl(device).DestroySwapchainKHR(device, swapchain);
+}
+
+__attribute__((visibility("default")))
+VkResult vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pCount, VkImage* pSwapchainImages) {
+    return GetVtbl(device).GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
+}
+
+__attribute__((visibility("default")))
+VkResult vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, uint32_t* pImageIndex) {
+    return GetVtbl(device).AcquireNextImageKHR(device, swapchain, timeout, semaphore, pImageIndex);
+}
+
+__attribute__((visibility("default")))
+VkResult vkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo) {
+    return GetVtbl(queue).QueuePresentKHR(queue, pPresentInfo);
+}
diff --git a/vulkan/libvulkan/entry.cpp.tmpl b/vulkan/libvulkan/entry.cpp.tmpl
index 352ac59..4e671e5 100644
--- a/vulkan/libvulkan/entry.cpp.tmpl
+++ b/vulkan/libvulkan/entry.cpp.tmpl
@@ -78,6 +78,53 @@
       {{end}}
     {{end}}
   {{end}}
+
+{{/* Extension functions aren't in the API file yet, so must be special-cased */}}
+__attribute__((visibility("default")))
+VkResult vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkBool32* pSupported) {
+    return GetVtbl(physicalDevice).GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, pSurfaceDescription, pSupported);
+}

+__attribute__((visibility("default")))
+VkResult vkGetSurfacePropertiesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkSurfacePropertiesKHR* pSurfaceProperties) {
+    return GetVtbl(device).GetSurfacePropertiesKHR(device, pSurfaceDescription, pSurfaceProperties);
+}

+__attribute__((visibility("default")))
+VkResult vkGetSurfaceFormatsKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkSurfaceFormatKHR* pSurfaceFormats) {
+    return GetVtbl(device).GetSurfaceFormatsKHR(device, pSurfaceDescription, pCount, pSurfaceFormats);
+}

+__attribute__((visibility("default")))
+VkResult vkGetSurfacePresentModesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkPresentModeKHR* pPresentModes) {
+    return GetVtbl(device).GetSurfacePresentModesKHR(device, pSurfaceDescription, pCount, pPresentModes);
+}

+__attribute__((visibility("default")))
+VkResult vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain) {
+    return GetVtbl(device).CreateSwapchainKHR(device, pCreateInfo, pSwapchain);
+}

+__attribute__((visibility("default")))
+VkResult vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain) {
+    return GetVtbl(device).DestroySwapchainKHR(device, swapchain);
+}

+__attribute__((visibility("default")))
+VkResult vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pCount, VkImage* pSwapchainImages) {
+    return GetVtbl(device).GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
+}

+__attribute__((visibility("default")))
+VkResult vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, uint32_t* pImageIndex) {
+    return GetVtbl(device).AcquireNextImageKHR(device, swapchain, timeout, semaphore, pImageIndex);
+}

+__attribute__((visibility("default")))
+VkResult vkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo) {
+    return GetVtbl(queue).QueuePresentKHR(queue, pPresentInfo);
+}

 {{end}}
 
 
diff --git a/vulkan/libvulkan/get_proc_addr.cpp b/vulkan/libvulkan/get_proc_addr.cpp
index 5f05f0e..ba38bff 100644
--- a/vulkan/libvulkan/get_proc_addr.cpp
+++ b/vulkan/libvulkan/get_proc_addr.cpp
@@ -370,21 +370,54 @@
 namespace vulkan {
 
 PFN_vkVoidFunction GetGlobalInstanceProcAddr(const char* name) {
+    const NameProcEntry* entry = FindProcEntry(kInstanceProcTbl, name);
+    if (entry)
+        return entry->proc;
+    // vkGetDeviceProcAddr must be available at the global/instance level for
+    // bootstrapping
     if (strcmp(name, "vkGetDeviceProcAddr") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(vkGetDeviceProcAddr);
-    const NameProcEntry* entry = FindProcEntry(kInstanceProcTbl, name);
-    return entry ? entry->proc : nullptr;
+    // special-case extension functions until they can be auto-generated
+    if (strcmp(name, "vkGetPhysicalDeviceSurfaceSupportKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            vkGetPhysicalDeviceSurfaceSupportKHR);
+    return nullptr;
 }
 
 PFN_vkVoidFunction GetGlobalDeviceProcAddr(const char* name) {
     const NameProcEntry* entry = FindProcEntry(kDeviceProcTbl, name);
-    return entry ? entry->proc : nullptr;
+    if (entry)
+        return entry->proc;
+    // special-case extension functions until they can be auto-generated
+    if (strcmp(name, "vkGetSurfacePropertiesKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePropertiesKHR);
+    if (strcmp(name, "vkGetSurfaceFormatsKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfaceFormatsKHR);
+    if (strcmp(name, "vkGetSurfacePresentModesKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            vkGetSurfacePresentModesKHR);
+    if (strcmp(name, "vkCreateSwapchainKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkCreateSwapchainKHR);
+    if (strcmp(name, "vkDestroySwapchainKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkDestroySwapchainKHR);
+    if (strcmp(name, "vkGetSwapchainImagesKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetSwapchainImagesKHR);
+    if (strcmp(name, "vkAcquireNextImageKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkAcquireNextImageKHR);
+    if (strcmp(name, "vkQueuePresentKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkQueuePresentKHR);
+    return nullptr;
 }
 
 PFN_vkVoidFunction GetSpecificInstanceProcAddr(const InstanceVtbl* vtbl,
                                                const char* name) {
+    size_t offset;
     const NameOffsetEntry* entry = FindProcEntry(kInstanceOffsetTbl, name);
-    if (!entry)
+    if (entry)
+        offset = entry->offset;
+    else if (strcmp(name, "vkGetPhysicalDeviceSurfaceSupportKHR") == 0)
+        offset = offsetof(InstanceVtbl, GetPhysicalDeviceSurfaceSupportKHR);
+    else
         return nullptr;
     const unsigned char* base = reinterpret_cast<const unsigned char*>(vtbl);
     return reinterpret_cast<PFN_vkVoidFunction>(
@@ -393,8 +426,27 @@
 
 PFN_vkVoidFunction GetSpecificDeviceProcAddr(const DeviceVtbl* vtbl,
                                              const char* name) {
+    size_t offset;
     const NameOffsetEntry* entry = FindProcEntry(kDeviceOffsetTbl, name);
-    if (!entry)
+    if (entry)
+        offset = entry->offset;
+    else if (strcmp(name, "vkGetSurfacePropertiesKHR") == 0)
+        offset = offsetof(DeviceVtbl, GetSurfacePropertiesKHR);
+    else if (strcmp(name, "vkGetSurfaceFormatsKHR") == 0)
+        offset = offsetof(DeviceVtbl, GetSurfaceFormatsKHR);
+    else if (strcmp(name, "vkGetSurfacePresentModesKHR") == 0)
+        offset = offsetof(DeviceVtbl, GetSurfacePresentModesKHR);
+    else if (strcmp(name, "vkCreateSwapchainKHR") == 0)
+        offset = offsetof(DeviceVtbl, CreateSwapchainKHR);
+    else if (strcmp(name, "vkDestroySwapchainKHR") == 0)
+        offset = offsetof(DeviceVtbl, DestroySwapchainKHR);
+    else if (strcmp(name, "vkGetSwapchainImagesKHR") == 0)
+        offset = offsetof(DeviceVtbl, GetSwapchainImagesKHR);
+    else if (strcmp(name, "vkAcquireNextImageKHR") == 0)
+        offset = offsetof(DeviceVtbl, AcquireNextImageKHR);
+    else if (strcmp(name, "vkQueuePresentKHR") == 0)
+        offset = offsetof(DeviceVtbl, QueuePresentKHR);
+    else
         return nullptr;
     const unsigned char* base = reinterpret_cast<const unsigned char*>(vtbl);
     return reinterpret_cast<PFN_vkVoidFunction>(
@@ -1160,6 +1212,16 @@
         ALOGE("missing device proc: %s", "vkCmdExecuteCommands");
         success = false;
     }
+    vtbl.ImportNativeFenceANDROID = reinterpret_cast<PFN_vkImportNativeFenceANDROID>(get_proc_addr(device, "vkImportNativeFenceANDROID"));
+    if (UNLIKELY(!vtbl.ImportNativeFenceANDROID)) {
+        ALOGE("missing device proc: %s", "vkImportNativeFenceANDROID");
+        success = false;
+    }
+    vtbl.QueueSignalNativeFenceANDROID = reinterpret_cast<PFN_vkQueueSignalNativeFenceANDROID>(get_proc_addr(device, "vkQueueSignalNativeFenceANDROID"));
+    if (UNLIKELY(!vtbl.QueueSignalNativeFenceANDROID)) {
+        ALOGE("missing device proc: %s", "vkQueueSignalNativeFenceANDROID");
+        success = false;
+    }
     // clang-format on
     return success;
 }
diff --git a/vulkan/libvulkan/get_proc_addr.cpp.tmpl b/vulkan/libvulkan/get_proc_addr.cpp.tmpl
index c3391e1..bbbb2a0 100644
--- a/vulkan/libvulkan/get_proc_addr.cpp.tmpl
+++ b/vulkan/libvulkan/get_proc_addr.cpp.tmpl
@@ -120,21 +120,51 @@
 namespace vulkan {

 PFN_vkVoidFunction GetGlobalInstanceProcAddr(const char* name) {
+    const NameProcEntry* entry = FindProcEntry(kInstanceProcTbl, name);
+    if (entry)
+        return entry->proc;
+    // vkGetDeviceProcAddr must be available at the global/instance level for bootstrapping
     if (strcmp(name, "vkGetDeviceProcAddr") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(vkGetDeviceProcAddr);
-    const NameProcEntry* entry = FindProcEntry(kInstanceProcTbl, name);
-    return entry ? entry->proc : nullptr;
+    // special-case extension functions until they can be auto-generated
+    if (strcmp(name, "vkGetPhysicalDeviceSurfaceSupportKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetPhysicalDeviceSurfaceSupportKHR);
+    return nullptr;
 }

 PFN_vkVoidFunction GetGlobalDeviceProcAddr(const char* name) {
     const NameProcEntry* entry = FindProcEntry(kDeviceProcTbl, name);
-    return entry ? entry->proc : nullptr;
+    if (entry)
+        return entry->proc;
+    // special-case extension functions until they can be auto-generated
+    if (strcmp(name, "vkGetSurfacePropertiesKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePropertiesKHR);
+    if (strcmp(name, "vkGetSurfaceFormatsKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfaceFormatsKHR);
+    if (strcmp(name, "vkGetSurfacePresentModesKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePresentModesKHR);
+    if (strcmp(name, "vkCreateSwapchainKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkCreateSwapchainKHR);
+    if (strcmp(name, "vkDestroySwapchainKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkDestroySwapchainKHR);
+    if (strcmp(name, "vkGetSwapchainImagesKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetSwapchainImagesKHR);
+    if (strcmp(name, "vkAcquireNextImageKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkAcquireNextImageKHR);
+    if (strcmp(name, "vkQueuePresentKHR") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(vkQueuePresentKHR);
+    return nullptr;
 }

 PFN_vkVoidFunction GetSpecificInstanceProcAddr(const InstanceVtbl* vtbl,
                                                const char* name) {
+    size_t offset;
     const NameOffsetEntry* entry = FindProcEntry(kInstanceOffsetTbl, name);
-    if (!entry)
+    if (entry)
+        offset = entry->offset;
+    else if (strcmp(name, "vkGetPhysicalDeviceSurfaceSupportKHR") == 0)
+        offset = offsetof(InstanceVtbl, GetPhysicalDeviceSurfaceSupportKHR);
+    else
         return nullptr;
     const unsigned char* base = reinterpret_cast<const unsigned char*>(vtbl);
     return reinterpret_cast<PFN_vkVoidFunction>(
@@ -143,8 +173,27 @@

 PFN_vkVoidFunction GetSpecificDeviceProcAddr(const DeviceVtbl* vtbl,
                                              const char* name) {
+    size_t offset;
     const NameOffsetEntry* entry = FindProcEntry(kDeviceOffsetTbl, name);
-    if (!entry)
+    if (entry)
+        offset = entry->offset;
+    else if (strcmp(name, "vkGetSurfacePropertiesKHR") == 0)
+        offset = offsetof(DeviceVtbl, GetSurfacePropertiesKHR);
+    else if (strcmp(name, "vkGetSurfaceFormatsKHR") == 0)
+        offset = offsetof(DeviceVtbl, GetSurfaceFormatsKHR);
+    else if (strcmp(name, "vkGetSurfacePresentModesKHR") == 0)
+        offset = offsetof(DeviceVtbl, GetSurfacePresentModesKHR);
+    else if (strcmp(name, "vkCreateSwapchainKHR") == 0)
+        offset = offsetof(DeviceVtbl, CreateSwapchainKHR);
+    else if (strcmp(name, "vkDestroySwapchainKHR") == 0)
+        offset = offsetof(DeviceVtbl, DestroySwapchainKHR);
+    else if (strcmp(name, "vkGetSwapchainImagesKHR") == 0)
+        offset = offsetof(DeviceVtbl, GetSwapchainImagesKHR);
+    else if (strcmp(name, "vkAcquireNextImageKHR") == 0)
+        offset = offsetof(DeviceVtbl, AcquireNextImageKHR);
+    else if (strcmp(name, "vkQueuePresentKHR") == 0)
+        offset = offsetof(DeviceVtbl, QueuePresentKHR);
+    else
         return nullptr;
     const unsigned char* base = reinterpret_cast<const unsigned char*>(vtbl);
     return reinterpret_cast<PFN_vkVoidFunction>(
@@ -187,6 +236,16 @@
     }
       {{end}}
     {{end}}
+    vtbl.ImportNativeFenceANDROID = reinterpret_cast<PFN_vkImportNativeFenceANDROID>(get_proc_addr(device, "vkImportNativeFenceANDROID"));
+    if (UNLIKELY(!vtbl.ImportNativeFenceANDROID)) {
+        ALOGE("missing device proc: %s", "vkImportNativeFenceANDROID");
+        success = false;
+    }
+    vtbl.QueueSignalNativeFenceANDROID = reinterpret_cast<PFN_vkQueueSignalNativeFenceANDROID>(get_proc_addr(device, "vkQueueSignalNativeFenceANDROID"));
+    if (UNLIKELY(!vtbl.QueueSignalNativeFenceANDROID)) {
+        ALOGE("missing device proc: %s", "vkQueueSignalNativeFenceANDROID");
+        success = false;
+    }
     // clang-format on
     return success;
 »}
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 41425e9..26b1377 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -342,6 +342,15 @@
     }
     dispatch->vtbl = &device->vtbl_storage;
 
+    device->vtbl_storage.GetSurfacePropertiesKHR = GetSurfacePropertiesKHR;
+    device->vtbl_storage.GetSurfaceFormatsKHR = GetSurfaceFormatsKHR;
+    device->vtbl_storage.GetSurfacePresentModesKHR = GetSurfacePresentModesKHR;
+    device->vtbl_storage.CreateSwapchainKHR = CreateSwapchainKHR;
+    device->vtbl_storage.DestroySwapchainKHR = DestroySwapchainKHR;
+    device->vtbl_storage.GetSwapchainImagesKHR = GetSwapchainImagesKHR;
+    device->vtbl_storage.AcquireNextImageKHR = AcquireNextImageKHR;
+    device->vtbl_storage.QueuePresentKHR = QueuePresentKHR;
+
     // TODO: insert device layer entry points into device->vtbl_storage here?
 
     *out_device = drv_device;
@@ -402,6 +411,7 @@
     .GetPhysicalDeviceExtensionProperties = GetPhysicalDeviceExtensionPropertiesBottom,
     .GetPhysicalDeviceLayerProperties = GetPhysicalDeviceLayerPropertiesBottom,
     .GetPhysicalDeviceSparseImageFormatProperties = GetPhysicalDeviceSparseImageFormatPropertiesBottom,
+    .GetPhysicalDeviceSurfaceSupportKHR = GetPhysicalDeviceSurfaceSupportKHR,
     // clang-format on
 };
 
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index f3a59fd..db5c4d3 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -19,9 +19,18 @@
 
 #define VK_PROTOTYPES
 #include <vulkan/vulkan.h>
+#include <vulkan/vk_ext_khr_swapchain.h>
+#include <vulkan/vk_ext_khr_device_swapchain.h>
+#include <vulkan/vk_ext_android_native_buffer.h>
 
 namespace vulkan {
 
+// TODO(jessehall): The InstanceVtbl and DeviceVtbl both have a set of
+// functions used in the app->layers/loader interface, and a different set of
+// functions used only in the loader->driver interface. We should probably
+// split them into two structures: one used for dispatch of application calls,
+// and one to hold the driver entry points.
+
 struct InstanceVtbl {
     // clang-format off
     VkInstance instance;
@@ -43,6 +52,9 @@
     PFN_vkGetPhysicalDeviceExtensionProperties GetPhysicalDeviceExtensionProperties;
     PFN_vkGetPhysicalDeviceLayerProperties GetPhysicalDeviceLayerProperties;
     PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
+
+    // Layers and loader only, not implemented by drivers
+    PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
     // clang-format on
 };
 
@@ -185,6 +197,20 @@
     PFN_vkCmdNextSubpass CmdNextSubpass;
     PFN_vkCmdEndRenderPass CmdEndRenderPass;
     PFN_vkCmdExecuteCommands CmdExecuteCommands;
+
+    // Layers and loader only, not implemented by drivers
+    PFN_vkGetSurfacePropertiesKHR GetSurfacePropertiesKHR;
+    PFN_vkGetSurfaceFormatsKHR GetSurfaceFormatsKHR;
+    PFN_vkGetSurfacePresentModesKHR GetSurfacePresentModesKHR;
+    PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
+    PFN_vkDestroySwapchainKHR DestroySwapchainKHR;
+    PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
+    PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
+    PFN_vkQueuePresentKHR QueuePresentKHR;
+
+    // Implemented only by drivers, not by layers or the loader
+    PFN_vkImportNativeFenceANDROID ImportNativeFenceANDROID;
+    PFN_vkQueueSignalNativeFenceANDROID QueueSignalNativeFenceANDROID;
 };
 
 // -----------------------------------------------------------------------------
@@ -225,6 +251,40 @@
                     PFN_vkGetDeviceProcAddr get_proc_addr,
                     DeviceVtbl& vtbl);
 
+// -----------------------------------------------------------------------------
+// swapchain.cpp
+
+VkResult GetPhysicalDeviceSurfaceSupportKHR(
+    VkPhysicalDevice pdev,
+    uint32_t queue_family,
+    const VkSurfaceDescriptionKHR* surface_desc,
+    VkBool32* supported);
+VkResult GetSurfacePropertiesKHR(VkDevice device,
+                                 const VkSurfaceDescriptionKHR* surface_desc,
+                                 VkSurfacePropertiesKHR* properties);
+VkResult GetSurfaceFormatsKHR(VkDevice device,
+                              const VkSurfaceDescriptionKHR* surface_desc,
+                              uint32_t* count,
+                              VkSurfaceFormatKHR* formats);
+VkResult GetSurfacePresentModesKHR(VkDevice device,
+                                   const VkSurfaceDescriptionKHR* surface_desc,
+                                   uint32_t* count,
+                                   VkPresentModeKHR* modes);
+VkResult CreateSwapchainKHR(VkDevice device,
+                            const VkSwapchainCreateInfoKHR* create_info,
+                            VkSwapchainKHR* swapchain);
+VkResult DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain);
+VkResult GetSwapchainImagesKHR(VkDevice device,
+                               VkSwapchainKHR swapchain,
+                               uint32_t* count,
+                               VkImage* image);
+VkResult AcquireNextImageKHR(VkDevice device,
+                             VkSwapchainKHR swapchain,
+                             uint64_t timeout,
+                             VkSemaphore semaphore,
+                             uint32_t* image_index);
+VkResult QueuePresentKHR(VkQueue queue, VkPresentInfoKHR* present_info);
+
 }  // namespace vulkan
 
 #endif  // LIBVULKAN_LOADER_H
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
new file mode 100644
index 0000000..7db5869
--- /dev/null
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "loader.h"
+#define LOG_NDEBUG 0
+#include <log/log.h>
+
+namespace vulkan {
+
+VkResult GetPhysicalDeviceSurfaceSupportKHR(
+    VkPhysicalDevice /*pdev*/,
+    uint32_t /*queue_family*/,
+    const VkSurfaceDescriptionKHR* surface_desc,
+    VkBool32* supported) {
+// TODO(jessehall): Fix the header, preferrably upstream, so values added to
+// existing enums don't trigger warnings like this.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+    if (surface_desc->sType != VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR)
+        return VK_ERROR_INVALID_VALUE;
+#pragma clang diagnostic pop
+
+    const VkSurfaceDescriptionWindowKHR* window_desc =
+        reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(surface_desc);
+
+    // TODO(jessehall): Also check whether the physical device exports the
+    // VK_EXT_ANDROID_native_buffer extension. For now, assume it does.
+    *supported = (window_desc->platform == VK_PLATFORM_ANDROID_KHR &&
+                  !window_desc->pPlatformHandle &&
+                  static_cast<ANativeWindow*>(window_desc->pPlatformWindow)
+                          ->common.magic == ANDROID_NATIVE_WINDOW_MAGIC);
+
+    return VK_SUCCESS;
+}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+VkResult GetSurfacePropertiesKHR(VkDevice device,
+                                 const VkSurfaceDescriptionKHR* surface_desc,
+                                 VkSurfacePropertiesKHR* properties) {
+    ALOGV("TODO: %s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult GetSurfaceFormatsKHR(VkDevice device,
+                              const VkSurfaceDescriptionKHR* surface_desc,
+                              uint32_t* count,
+                              VkSurfaceFormatKHR* formats) {
+    ALOGV("TODO: %s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult GetSurfacePresentModesKHR(VkDevice device,
+                                   const VkSurfaceDescriptionKHR* surface_desc,
+                                   uint32_t* count,
+                                   VkPresentModeKHR* modes) {
+    ALOGV("TODO: %s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult CreateSwapchainKHR(VkDevice device,
+                            const VkSwapchainCreateInfoKHR* create_info,
+                            VkSwapchainKHR* swapchain) {
+    ALOGV("TODO: %s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain) {
+    ALOGV("TODO: %s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult GetSwapchainImagesKHR(VkDevice device,
+                               VkSwapchainKHR swapchain,
+                               uint32_t* count,
+                               VkImage* image) {
+    ALOGV("TODO: %s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult AcquireNextImageKHR(VkDevice device,
+                             VkSwapchainKHR swapchain,
+                             uint64_t timeout,
+                             VkSemaphore semaphore,
+                             uint32_t* image_index) {
+    ALOGV("TODO: %s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult QueuePresentKHR(VkQueue queue, VkPresentInfoKHR* present_info) {
+    ALOGV("TODO: %s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+#pragma clang diagnostic pop
+
+}  // namespace vulkan
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 0a15818..766abc9 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -137,6 +137,11 @@
 
 VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
                         VkInstance* out_instance) {
+    // Assume the loader provided alloc callbacks even if the app didn't.
+    ALOG_ASSERT(
+        !create_info->pAllocCb,
+        "Missing alloc callbacks, loader or app should have provided them");
+
     VkInstance_T* instance =
         static_cast<VkInstance_T*>(create_info->pAllocCb->pfnAlloc(
             create_info->pAllocCb->pUserData, sizeof(VkInstance_T),
@@ -231,7 +236,15 @@
 }
 
 PFN_vkVoidFunction GetDeviceProcAddr(VkDevice, const char* name) {
-    return LookupDeviceProcAddr(name);
+    PFN_vkVoidFunction proc = LookupDeviceProcAddr(name);
+    if (proc)
+        return proc;
+    if (strcmp(name, "vkImportNativeFenceANDROID") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(ImportNativeFenceANDROID);
+    if (strcmp(name, "vkQueueSignalNativeFenceANDROID") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            QueueSignalNativeFenceANDROID);
+    return nullptr;
 }
 
 // -----------------------------------------------------------------------------
@@ -1110,6 +1123,16 @@
 void CmdExecuteCommands(VkCmdBuffer cmdBuffer, uint32_t cmdBuffersCount, const VkCmdBuffer* pCmdBuffers) {
 }
 
+VkResult ImportNativeFenceANDROID(VkDevice device, VkSemaphore semaphore, int nativeFenceFd) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult QueueSignalNativeFenceANDROID(VkQueue queue, int* pNativeFenceFd) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
 #pragma clang diagnostic pop
 // clang-format on
 
diff --git a/vulkan/nulldrv/null_driver.h b/vulkan/nulldrv/null_driver.h
index c6c7aa6..6bfbda5 100644
--- a/vulkan/nulldrv/null_driver.h
+++ b/vulkan/nulldrv/null_driver.h
@@ -19,6 +19,7 @@
 
 #define VK_PROTOTYPES
 #include <vulkan/vulkan.h>
+#include <vulkan/vk_ext_android_native_buffer.h>
 
 namespace null_driver {
 
@@ -177,6 +178,9 @@
 void CmdNextSubpass(VkCmdBuffer cmdBuffer, VkRenderPassContents contents);
 void CmdEndRenderPass(VkCmdBuffer cmdBuffer);
 void CmdExecuteCommands(VkCmdBuffer cmdBuffer, uint32_t cmdBuffersCount, const VkCmdBuffer* pCmdBuffers);
+
+VkResult ImportNativeFenceANDROID(VkDevice device, VkSemaphore semaphore, int nativeFenceFd);
+VkResult QueueSignalNativeFenceANDROID(VkQueue queue, int* pNativeFenceFd);
 // clang-format on
 
 }  // namespace null_driver