Merge changes Idf479bed,Iee7d56c1,I23d7945e,Ibd6fa875,I52f7afb4, ...
* changes:
vulkan: Add apk_library_dir virtual branch
Add support for loading layers from the apk.
Add default callbacks in the loader.
Add support for arbitrary number of layers
Add support for autoloading callback extension.
Add support for multiple layers in the same so
Add layer loading to android vulkan loader.
Fix GetSpecific*ProcAddr.
vulkan: Implement vk_ext_khr_*swapchain extensions
vulkan: Add skeleton swapchain support
vulkan: add copyright notices
vknulldrv: Implement VkImage
vulkan: warn on bogus CreateBuffer args
diff --git a/vulkan/include/vulkan/vk_debug_report_lunarg.h b/vulkan/include/vulkan/vk_debug_report_lunarg.h
new file mode 100644
index 0000000..8ff5654
--- /dev/null
+++ b/vulkan/include/vulkan/vk_debug_report_lunarg.h
@@ -0,0 +1,188 @@
+//
+// File: vk_debug_report_lunarg.h
+//
+/*
+ * Vulkan
+ *
+ * Copyright (C) 2015 LunarG, Inc.
+ *
+ * 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.
+ *
+ * Authors:
+ * Jon Ashburn <jon@lunarg.com>
+ * Courtney Goeltzenleuchter <courtney@lunarg.com>
+ */
+
+#ifndef __VK_DEBUG_REPORT_LUNARG_H__
+#define __VK_DEBUG_REPORT_LUNARG_H__
+
+#include <vulkan/vulkan.h>
+
+#define VK_DEBUG_REPORT_EXTENSION_NUMBER 5
+#define VK_DEBUG_REPORT_EXTENSION_REVISION 1
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/*
+***************************************************************************************************
+* DebugReport Vulkan Extension API
+***************************************************************************************************
+*/
+typedef enum {
+ VK_OBJECT_TYPE_INSTANCE = 0,
+ VK_OBJECT_TYPE_PHYSICAL_DEVICE = 1,
+ VK_OBJECT_TYPE_DEVICE = 2,
+ VK_OBJECT_TYPE_QUEUE = 3,
+ VK_OBJECT_TYPE_COMMAND_BUFFER = 4,
+ VK_OBJECT_TYPE_DEVICE_MEMORY = 5,
+ VK_OBJECT_TYPE_BUFFER = 6,
+ VK_OBJECT_TYPE_BUFFER_VIEW = 7,
+ VK_OBJECT_TYPE_IMAGE = 8,
+ VK_OBJECT_TYPE_IMAGE_VIEW = 9,
+ VK_OBJECT_TYPE_ATTACHMENT_VIEW = 10,
+ VK_OBJECT_TYPE_SHADER_MODULE = 12,
+ VK_OBJECT_TYPE_SHADER = 13,
+ VK_OBJECT_TYPE_PIPELINE = 14,
+ VK_OBJECT_TYPE_PIPELINE_LAYOUT = 15,
+ VK_OBJECT_TYPE_SAMPLER = 16,
+ VK_OBJECT_TYPE_DESCRIPTOR_SET = 17,
+ VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 18,
+ VK_OBJECT_TYPE_DESCRIPTOR_POOL = 19,
+ VK_OBJECT_TYPE_DYNAMIC_VIEWPORT_STATE = 20,
+ VK_OBJECT_TYPE_DYNAMIC_LINE_WIDTH_STATE = 21,
+ VK_OBJECT_TYPE_DYNAMIC_DEPTH_BIAS_STATE = 22,
+ VK_OBJECT_TYPE_DYNAMIC_BLEND_STATE = 23,
+ VK_OBJECT_TYPE_DYNAMIC_DEPTH_BOUNDS_STATE = 24,
+ VK_OBJECT_TYPE_DYNAMIC_STENCIL_STATE = 25,
+ VK_OBJECT_TYPE_FENCE = 26,
+ VK_OBJECT_TYPE_SEMAPHORE = 27,
+ VK_OBJECT_TYPE_EVENT = 28,
+ VK_OBJECT_TYPE_QUERY_POOL = 29,
+ VK_OBJECT_TYPE_FRAMEBUFFER = 30,
+ VK_OBJECT_TYPE_RENDER_PASS = 31,
+ VK_OBJECT_TYPE_PIPELINE_CACHE = 32,
+ VK_OBJECT_TYPE_SWAPCHAIN_KHR = 33,
+ VK_OBJECT_TYPE_CMD_POOL = 34,
+ VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_INSTANCE,
+ VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_CMD_POOL,
+ VK_OBJECT_TYPE_NUM =
+ (VK_OBJECT_TYPE_CMD_POOL - VK_OBJECT_TYPE_INSTANCE + 1),
+ VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkDbgObjectType;
+
+#define VK_DEBUG_REPORT_EXTENSION_NAME "DEBUG_REPORT"
+
+VK_DEFINE_NONDISP_HANDLE(VkDbgMsgCallback)
+
+// ------------------------------------------------------------------------------------------------
+// Enumerations
+
+typedef enum VkDbgReportFlags_ {
+ VK_DBG_REPORT_INFO_BIT = 0x0001,
+ VK_DBG_REPORT_WARN_BIT = 0x0002,
+ VK_DBG_REPORT_PERF_WARN_BIT = 0x0004,
+ VK_DBG_REPORT_ERROR_BIT = 0x0008,
+ VK_DBG_REPORT_DEBUG_BIT = 0x0010,
+} VkDbgReportFlags;
+
+// Debug Report ERROR codes
+typedef enum _DEBUG_REPORT_ERROR {
+ DEBUG_REPORT_NONE, // Used for INFO & other non-error messages
+ DEBUG_REPORT_CALLBACK_REF, // Callbacks were not destroyed prior to calling
+ // DestroyInstance
+} DEBUG_REPORT_ERROR;
+
+#define VK_DEBUG_REPORT_ENUM_EXTEND(type, id) \
+ ((type)(VK_DEBUG_REPORT_EXTENSION_NUMBER * -1000 + (id)))
+
+#define VK_OBJECT_TYPE_MSG_CALLBACK \
+ VK_DEBUG_REPORT_ENUM_EXTEND(VkDbgObjectType, 0)
+// ------------------------------------------------------------------------------------------------
+// Vulkan function pointers
+
+typedef void (*PFN_vkDbgMsgCallback)(VkFlags msgFlags,
+ VkDbgObjectType objType,
+ uint64_t srcObject,
+ size_t location,
+ int32_t msgCode,
+ const char* pLayerPrefix,
+ const char* pMsg,
+ void* pUserData);
+
+// ------------------------------------------------------------------------------------------------
+// API functions
+
+typedef VkResult(VKAPI* PFN_vkDbgCreateMsgCallback)(
+ VkInstance instance,
+ VkFlags msgFlags,
+ const PFN_vkDbgMsgCallback pfnMsgCallback,
+ void* pUserData,
+ VkDbgMsgCallback* pMsgCallback);
+typedef VkResult(VKAPI* PFN_vkDbgDestroyMsgCallback)(
+ VkInstance instance,
+ VkDbgMsgCallback msgCallback);
+
+#ifdef VK_PROTOTYPES
+
+// DebugReport extension entrypoints
+VkResult VKAPI vkDbgCreateMsgCallback(VkInstance instance,
+ VkFlags msgFlags,
+ const PFN_vkDbgMsgCallback pfnMsgCallback,
+ void* pUserData,
+ VkDbgMsgCallback* pMsgCallback);
+
+VkResult VKAPI vkDbgDestroyMsgCallback(VkInstance instance,
+ VkDbgMsgCallback msgCallback);
+
+// DebugReport utility callback functions
+void VKAPI vkDbgStringCallback(VkFlags msgFlags,
+ VkDbgObjectType objType,
+ uint64_t srcObject,
+ size_t location,
+ int32_t msgCode,
+ const char* pLayerPrefix,
+ const char* pMsg,
+ void* pUserData);
+
+void VKAPI vkDbgStdioCallback(VkFlags msgFlags,
+ VkDbgObjectType objType,
+ uint64_t srcObject,
+ size_t location,
+ int32_t msgCode,
+ const char* pLayerPrefix,
+ const char* pMsg,
+ void* pUserData);
+
+void VKAPI vkDbgBreakCallback(VkFlags msgFlags,
+ VkDbgObjectType objType,
+ uint64_t srcObject,
+ size_t location,
+ int32_t msgCode,
+ const char* pLayerPrefix,
+ const char* pMsg,
+ void* pUserData);
+
+#endif // VK_PROTOTYPES
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif // __VK_DEBUG_REPORT_LUNARG_H__
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/include/vulkan/vulkan_loader_data.h b/vulkan/include/vulkan/vulkan_loader_data.h
new file mode 100644
index 0000000..968a7aa
--- /dev/null
+++ b/vulkan/include/vulkan/vulkan_loader_data.h
@@ -0,0 +1,29 @@
+/*
+ * 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 VULKAN_VULKAN_LOADER_DATA_H
+#define VULKAN_VULKAN_LOADER_DATA_H
+
+#include <string>
+
+namespace vulkan {
+ struct LoaderData {
+ std::string layer_path;
+ __attribute__((visibility("default"))) static LoaderData& GetInstance();
+ };
+}
+
+#endif
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index c26b01f..7a2eb64 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -1,3 +1,17 @@
+# 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.
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -8,18 +22,22 @@
LOCAL_CPPFLAGS := -std=c++1y \
-Wno-c++98-compat-pedantic \
-Wno-exit-time-destructors \
- -Wno-c99-extensions
+ -Wno-c99-extensions \
+ -Wno-zero-length-array
LOCAL_C_INCLUDES := \
- frameworks/native/vulkan/include
+ frameworks/native/vulkan/include \
+ system/core/libsync/include
LOCAL_SRC_FILES := \
entry.cpp \
get_proc_addr.cpp \
- loader.cpp
+ loader.cpp \
+ swapchain.cpp \
+ vulkan_loader_data.cpp
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SHARED_LIBRARIES := libhardware liblog
+LOCAL_SHARED_LIBRARIES := libhardware liblog libsync libcutils
LOCAL_MODULE := libvulkan
include $(BUILD_SHARED_LIBRARY)
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 3eabe2e..4e671e5 100644
--- a/vulkan/libvulkan/entry.cpp.tmpl
+++ b/vulkan/libvulkan/entry.cpp.tmpl
@@ -1,3 +1,19 @@
+{{/*
+ * 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 "../api/templates/vulkan_common.tmpl"}}
{{Macro "DefineGlobals" $}}
{{$ | Macro "entry.cpp" | Reflow 4 | Write "entry.cpp"}}
@@ -62,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..ceb76b9 100644
--- a/vulkan/libvulkan/get_proc_addr.cpp
+++ b/vulkan/libvulkan/get_proc_addr.cpp
@@ -370,42 +370,105 @@
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>(
+ return *reinterpret_cast<PFN_vkVoidFunction*>(
const_cast<unsigned char*>(base) + entry->offset);
}
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>(
+ return *reinterpret_cast<PFN_vkVoidFunction*>(
const_cast<unsigned char*>(base) + entry->offset);
}
+// TODO: remove need for instance_next
bool LoadInstanceVtbl(VkInstance instance,
+ VkInstance instance_next,
PFN_vkGetInstanceProcAddr get_proc_addr,
InstanceVtbl& vtbl) {
bool success = true;
// clang-format off
+ vtbl.GetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(get_proc_addr(instance_next, "vkGetInstanceProcAddr"));
+ if (UNLIKELY(!vtbl.GetInstanceProcAddr)) {
+ ALOGE("missing instance proc: %s", "vkGetInstanceProcAddr");
+ success = false;
+ }
+ vtbl.CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(get_proc_addr(instance, "vkCreateInstance"));
+ if (UNLIKELY(!vtbl.CreateInstance)) {
+ // This is allowed to fail as the driver doesn't have to return vkCreateInstance when given an instance
+ }
vtbl.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(get_proc_addr(instance, "vkDestroyInstance"));
if (UNLIKELY(!vtbl.DestroyInstance)) {
ALOGE("missing instance proc: %s", "vkDestroyInstance");
@@ -416,11 +479,6 @@
ALOGE("missing instance proc: %s", "vkEnumeratePhysicalDevices");
success = false;
}
- vtbl.GetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(get_proc_addr(instance, "vkGetInstanceProcAddr"));
- if (UNLIKELY(!vtbl.GetInstanceProcAddr)) {
- ALOGE("missing instance proc: %s", "vkGetInstanceProcAddr");
- success = false;
- }
vtbl.GetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceProperties"));
if (UNLIKELY(!vtbl.GetPhysicalDeviceProperties)) {
ALOGE("missing instance proc: %s", "vkGetPhysicalDeviceProperties");
@@ -486,11 +544,12 @@
}
bool LoadDeviceVtbl(VkDevice device,
+ VkDevice device_next,
PFN_vkGetDeviceProcAddr get_proc_addr,
DeviceVtbl& vtbl) {
bool success = true;
// clang-format off
- vtbl.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(device, "vkGetDeviceProcAddr"));
+ vtbl.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(device_next, "vkGetDeviceProcAddr"));
if (UNLIKELY(!vtbl.GetDeviceProcAddr)) {
ALOGE("missing device proc: %s", "vkGetDeviceProcAddr");
success = false;
@@ -1160,6 +1219,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 d4ced56..2e63893 100644
--- a/vulkan/libvulkan/get_proc_addr.cpp.tmpl
+++ b/vulkan/libvulkan/get_proc_addr.cpp.tmpl
@@ -1,3 +1,19 @@
+{{/*
+ * 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 "../api/templates/vulkan_common.tmpl"}}
{{Global "clang-format" (Strings "clang-format" "-style=file")}}
{{Macro "DefineGlobals" $}}
@@ -104,44 +120,104 @@
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>(
+ return *reinterpret_cast<PFN_vkVoidFunction*>(
const_cast<unsigned char*>(base) + entry->offset);
}
¶
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>(
+ return *reinterpret_cast<PFN_vkVoidFunction*>(
const_cast<unsigned char*>(base) + entry->offset);
}
¶
bool LoadInstanceVtbl(VkInstance instance,
+ VkInstance instance_next,
PFN_vkGetInstanceProcAddr get_proc_addr,
InstanceVtbl& vtbl) {«
bool success = true;
// clang-format off
+ vtbl.GetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(get_proc_addr(instance_next, "vkGetInstanceProcAddr"));
+ if (UNLIKELY(!vtbl.GetInstanceProcAddr)) {
+ ALOGE("missing instance proc: %s", "vkGetInstanceProcAddr");
+ success = false;
+ }
+ vtbl.CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(get_proc_addr(instance, "vkCreateInstance"));
+ if (UNLIKELY(!vtbl.CreateInstance)) {
+ // This is allowed to fail as the driver doesn't have to return vkCreateInstance when given an instance
+ }
{{range $f := AllCommands $}}
{{if eq (Macro "Vtbl" $f) "Instance"}}
+ {{if not (eq (Macro "FunctionName" $f) "vkGetInstanceProcAddr")}}
vtbl.{{TrimPrefix "vk" (Macro "FunctionName" $f)}} = §
reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
get_proc_addr(instance, "{{Macro "FunctionName" $f}}"));
@@ -149,6 +225,7 @@
ALOGE("missing instance proc: %s", "{{Macro "FunctionName" $f}}");
success = false;
}
+ {{end}}
{{end}}
{{end}}
// clang-format on
@@ -156,12 +233,19 @@
»}
¶
bool LoadDeviceVtbl(VkDevice device,
+ VkDevice device_next,
PFN_vkGetDeviceProcAddr get_proc_addr,
DeviceVtbl& vtbl) {«
bool success = true;
// clang-format off
+ vtbl.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(device_next, "vkGetDeviceProcAddr"));
+ if (UNLIKELY(!vtbl.GetDeviceProcAddr)) {
+ ALOGE("missing device proc: %s", "vkGetDeviceProcAddr");
+ success = false;
+ }
{{range $f := AllCommands $}}
{{if eq (Macro "Vtbl" $f) "Device"}}
+ {{if not (eq (Macro "FunctionName" $f) "vkGetDeviceProcAddr")}}
vtbl.{{TrimPrefix "vk" (Macro "FunctionName" $f)}} = §
reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
get_proc_addr(device, "{{Macro "FunctionName" $f}}"));
@@ -169,8 +253,19 @@
ALOGE("missing device proc: %s", "{{Macro "FunctionName" $f}}");
success = false;
}
+ {{end}}
{{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 19ca9f2..97ceb4a 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -1,6 +1,24 @@
+/*
+ * 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.
+ */
+
// module header
#include "loader.h"
// standard C headers
+#include <dirent.h>
+#include <dlfcn.h>
#include <inttypes.h>
#include <malloc.h>
#include <pthread.h>
@@ -8,17 +26,103 @@
// standard C++ headers
#include <algorithm>
#include <mutex>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
// platform/library headers
+#include <cutils/properties.h>
#include <hardware/hwvulkan.h>
#include <log/log.h>
+#include <vulkan/vk_debug_report_lunarg.h>
+#include <vulkan/vulkan_loader_data.h>
using namespace vulkan;
static const uint32_t kMaxPhysicalDevices = 4;
+namespace {
+
+// These definitions are taken from the LunarG Vulkan Loader. They are used to
+// enforce compatability between the Loader and Layers.
+typedef void* (*PFN_vkGetProcAddr)(void* obj, const char* pName);
+
+typedef struct VkLayerLinkedListElem_ {
+ PFN_vkGetProcAddr get_proc_addr;
+ void* next_element;
+ void* base_object;
+} VkLayerLinkedListElem;
+
+// Define Handle typedef to be void* as returned from dlopen.
+typedef void* SharedLibraryHandle;
+
+// Custom versions of std classes that use the vulkan alloc callback.
+template <class T>
+class CallbackAllocator {
+ public:
+ typedef T value_type;
+
+ CallbackAllocator(const VkAllocCallbacks* alloc_input)
+ : alloc(alloc_input) {}
+
+ template <class T2>
+ CallbackAllocator(const CallbackAllocator<T2>& other)
+ : alloc(other.alloc) {}
+
+ T* allocate(std::size_t n) {
+ void* mem = alloc->pfnAlloc(alloc->pUserData, n * sizeof(T), alignof(T),
+ VK_SYSTEM_ALLOC_TYPE_INTERNAL);
+ return static_cast<T*>(mem);
+ }
+
+ void deallocate(T* array, std::size_t /*n*/) {
+ alloc->pfnFree(alloc->pUserData, array);
+ }
+
+ const VkAllocCallbacks* alloc;
+};
+// These are needed in order to move Strings
+template <class T>
+bool operator==(const CallbackAllocator<T>& alloc1,
+ const CallbackAllocator<T>& alloc2) {
+ return alloc1.alloc == alloc2.alloc;
+}
+template <class T>
+bool operator!=(const CallbackAllocator<T>& alloc1,
+ const CallbackAllocator<T>& alloc2) {
+ return !(alloc1 == alloc2);
+}
+
+template <class Key,
+ class T,
+ class Hash = std::hash<Key>,
+ class Pred = std::equal_to<Key> >
+using UnorderedMap =
+ std::unordered_map<Key,
+ T,
+ Hash,
+ Pred,
+ CallbackAllocator<std::pair<const Key, T> > >;
+
+template <class T>
+using Vector = std::vector<T, CallbackAllocator<T> >;
+
+typedef std::basic_string<char,
+ std::char_traits<char>,
+ CallbackAllocator<char> > String;
+
+} // namespace
+
+// -----------------------------------------------------------------------------
+
struct VkInstance_T {
VkInstance_T(const VkAllocCallbacks* alloc_callbacks)
- : vtbl(&vtbl_storage), alloc(alloc_callbacks), num_physical_devices(0) {
+ : vtbl(&vtbl_storage),
+ alloc(alloc_callbacks),
+ num_physical_devices(0),
+ active_layers(
+ CallbackAllocator<std::pair<String, SharedLibraryHandle> >(
+ alloc)) {
memset(&vtbl_storage, 0, sizeof(vtbl_storage));
memset(physical_devices, 0, sizeof(physical_devices));
memset(&drv.vtbl, 0, sizeof(drv.vtbl));
@@ -33,6 +137,9 @@
uint32_t num_physical_devices;
VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
+ Vector<std::pair<String, SharedLibraryHandle> > active_layers;
+ VkDbgMsgCallback message;
+
struct Driver {
// Pointers to driver entry points. Used explicitly by the loader; not
// set as the dispatch table for any objects.
@@ -61,6 +168,7 @@
}
DeviceVtbl vtbl_storage;
const VkAllocCallbacks* alloc;
+ PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
};
// -----------------------------------------------------------------------------
@@ -73,6 +181,9 @@
inline const DeviceVtbl* GetVtbl(VkDevice device) {
return *reinterpret_cast<DeviceVtbl**>(device);
}
+inline const DeviceVtbl* GetVtbl(VkQueue queue) {
+ return *reinterpret_cast<DeviceVtbl**>(queue);
+}
void* DefaultAlloc(void*, size_t size, size_t alignment, VkSystemAllocType) {
return memalign(alignment, size);
@@ -122,6 +233,122 @@
alloc->pfnFree(alloc->pUserData, device);
}
+void FindLayersInDirectory(
+ Instance& instance,
+ UnorderedMap<String, SharedLibraryHandle>& layer_name_to_handle_map,
+ const String& dir_name) {
+ DIR* directory;
+ struct dirent* entry;
+ if ((directory = opendir(dir_name.c_str()))) {
+ Vector<VkLayerProperties> properties(
+ CallbackAllocator<VkLayerProperties>(instance.alloc));
+ while ((entry = readdir(directory))) {
+ size_t length = strlen(entry->d_name);
+ if (strncmp(entry->d_name, "libVKLayer", 10) != 0 ||
+ strncmp(entry->d_name + length - 3, ".so", 3) != 0)
+ continue;
+ // Open so
+ SharedLibraryHandle layer_handle = dlopen(
+ (dir_name + entry->d_name).c_str(), RTLD_NOW | RTLD_LOCAL);
+ if (!layer_handle) {
+ ALOGE("%s failed to load with error %s; Skipping",
+ entry->d_name, dlerror());
+ continue;
+ }
+
+ // Get Layers in so
+ PFN_vkGetGlobalLayerProperties get_layer_properties =
+ reinterpret_cast<PFN_vkGetGlobalLayerProperties>(
+ dlsym(layer_handle, "vkGetGlobalLayerProperties"));
+ if (!get_layer_properties) {
+ ALOGE(
+ "%s failed to find vkGetGlobalLayerProperties with "
+ "error %s; Skipping",
+ entry->d_name, dlerror());
+ dlclose(layer_handle);
+ continue;
+ }
+ uint32_t count;
+ get_layer_properties(&count, nullptr);
+
+ properties.resize(count);
+ get_layer_properties(&count, &properties[0]);
+
+ // Add Layers to potential list
+ for (uint32_t i = 0; i < count; ++i) {
+ layer_name_to_handle_map.insert(std::make_pair(
+ String(properties[i].layerName,
+ CallbackAllocator<char>(instance.alloc)),
+ layer_handle));
+ ALOGV("Found layer %s", properties[i].layerName);
+ }
+ }
+ closedir(directory);
+ } else {
+ ALOGE("Failed to Open Directory %s: %s (%d)", dir_name.c_str(),
+ strerror(errno), errno);
+ }
+}
+
+void LoadLayer(Instance* instance,
+ const String& name,
+ SharedLibraryHandle& layer_handle) {
+ ALOGV("Loading layer %s", name.c_str());
+ instance->active_layers.push_back(std::make_pair(name, layer_handle));
+}
+
+VkResult CreateDeviceNoop(VkPhysicalDevice,
+ const VkDeviceCreateInfo*,
+ VkDevice*) {
+ return VK_SUCCESS;
+}
+
+PFN_vkVoidFunction GetLayerDeviceProcAddr(VkDevice device, const char* name) {
+ if (strcmp(name, "vkGetDeviceProcAddr") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(GetLayerDeviceProcAddr);
+ }
+ if (strcmp(name, "vkCreateDevice") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(CreateDeviceNoop);
+ }
+ if (!device)
+ return GetGlobalDeviceProcAddr(name);
+ Device* loader_device = reinterpret_cast<Device*>(GetVtbl(device)->device);
+ return loader_device->GetDeviceProcAddr(device, name);
+}
+
+struct InstanceLayersPair {
+ Instance* instance;
+ UnorderedMap<String, SharedLibraryHandle>* layers;
+};
+
+void LoadLayerFromProperty(const char* name, const char* value, void* data) {
+ auto instance_layers_pair = static_cast<InstanceLayersPair*>(data);
+ const char prefix[] = "debug.vulkan.layer.";
+ const size_t prefixlen = sizeof(prefix) - 1;
+ if (value[0] == '\0' || strncmp(name, prefix, prefixlen) != 0)
+ return;
+ String layer_name_str(
+ name + prefixlen,
+ CallbackAllocator<char>(instance_layers_pair->instance->alloc));
+ LoadLayer(instance_layers_pair->instance, layer_name_str,
+ (*instance_layers_pair->layers)[layer_name_str]);
+}
+
+void LogDebugMessageCallback(VkFlags message_flags,
+ VkDbgObjectType /*obj_type*/,
+ uint64_t /*src_object*/,
+ size_t /*location*/,
+ int32_t message_code,
+ const char* layer_prefix,
+ const char* message,
+ void* /*user_data*/) {
+ if (message_flags & VK_DBG_REPORT_ERROR_BIT) {
+ ALOGE("[%s] Code %d : %s", layer_prefix, message_code, message);
+ } else if (message_flags & VK_DBG_REPORT_WARN_BIT) {
+ ALOGW("[%s] Code %d : %s", layer_prefix, message_code, message);
+ }
+}
+
// -----------------------------------------------------------------------------
// "Bottom" functions. These are called at the end of the instance dispatch
// chain.
@@ -133,6 +360,15 @@
instance->drv.vtbl.DestroyInstance) {
instance->drv.vtbl.DestroyInstance(instance->drv.vtbl.instance);
}
+ for (auto& layer : instance->active_layers) {
+ dlclose(layer.second);
+ }
+ if (instance->message) {
+ PFN_vkDbgDestroyMsgCallback DebugDestroyMessageCallback;
+ DebugDestroyMessageCallback = reinterpret_cast<PFN_vkDbgDestroyMsgCallback>(
+ vkGetInstanceProcAddr(instance, "vkDbgDestroyMsgCallback"));
+ DebugDestroyMessageCallback(instance, instance->message);
+ }
const VkAllocCallbacks* alloc = instance->alloc;
instance->~VkInstance_T();
alloc->pfnFree(alloc->pUserData, instance);
@@ -151,9 +387,9 @@
return result;
}
- if (!LoadInstanceVtbl(instance->drv.vtbl.instance,
- g_hwdevice->GetInstanceProcAddr,
- instance->drv.vtbl)) {
+ if (!LoadInstanceVtbl(
+ instance->drv.vtbl.instance, instance->drv.vtbl.instance,
+ g_hwdevice->GetInstanceProcAddr, instance->drv.vtbl)) {
DestroyInstanceBottom(instance);
return VK_ERROR_INITIALIZATION_FAILED;
}
@@ -300,6 +536,7 @@
if (!mem)
return VK_ERROR_OUT_OF_HOST_MEMORY;
Device* device = new (mem) Device(instance.alloc);
+ device->GetDeviceProcAddr = instance.drv.GetDeviceProcAddr;
VkDevice drv_device;
result = instance.drv.vtbl.CreateDevice(pdev, create_info, &drv_device);
@@ -308,25 +545,74 @@
return result;
}
- if (!LoadDeviceVtbl(drv_device, instance.drv.GetDeviceProcAddr,
- device->vtbl_storage)) {
- if (device->vtbl_storage.DestroyDevice)
- device->vtbl_storage.DestroyDevice(drv_device);
- DestroyDevice(device);
- return VK_ERROR_INITIALIZATION_FAILED;
- }
-
hwvulkan_dispatch_t* dispatch =
reinterpret_cast<hwvulkan_dispatch_t*>(drv_device);
if (dispatch->magic != HWVULKAN_DISPATCH_MAGIC) {
ALOGE("invalid VkDevice dispatch magic: 0x%" PRIxPTR, dispatch->magic);
- device->vtbl_storage.DestroyDevice(drv_device);
+ PFN_vkDestroyDevice destroy_device =
+ reinterpret_cast<PFN_vkDestroyDevice>(
+ instance.drv.GetDeviceProcAddr(drv_device, "vkDestroyDevice"));
+ destroy_device(drv_device);
DestroyDevice(device);
return VK_ERROR_INITIALIZATION_FAILED;
}
dispatch->vtbl = &device->vtbl_storage;
- // TODO: insert device layer entry points into device->vtbl_storage here?
+ 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;
+
+ void* base_object = static_cast<void*>(drv_device);
+ void* next_object = base_object;
+ VkLayerLinkedListElem* next_element;
+ PFN_vkGetDeviceProcAddr next_get_proc_addr = GetLayerDeviceProcAddr;
+ Vector<VkLayerLinkedListElem> elem_list(
+ instance.active_layers.size(),
+ CallbackAllocator<VkLayerLinkedListElem>(instance.alloc));
+
+ for (size_t i = elem_list.size(); i > 0; i--) {
+ size_t idx = i - 1;
+ next_element = &elem_list[idx];
+ next_element->get_proc_addr =
+ reinterpret_cast<PFN_vkGetProcAddr>(next_get_proc_addr);
+ next_element->base_object = base_object;
+ next_element->next_element = next_object;
+ next_object = static_cast<void*>(next_element);
+
+ auto& name_libhandle_pair = instance.active_layers[idx];
+ next_get_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+ dlsym(name_libhandle_pair.second,
+ (name_libhandle_pair.first + "GetDeviceProcAddr").c_str()));
+ if (!next_get_proc_addr) {
+ next_get_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+ dlsym(name_libhandle_pair.second, "vkGetDeviceProcAddr"));
+ if (!next_get_proc_addr) {
+ ALOGE("Cannot find vkGetDeviceProcAddr for %s, error is %s",
+ name_libhandle_pair.first.c_str(), dlerror());
+ next_object = next_element->next_element;
+ next_get_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+ next_element->get_proc_addr);
+ }
+ }
+ }
+
+ if (!LoadDeviceVtbl(static_cast<VkDevice>(base_object),
+ static_cast<VkDevice>(next_object), next_get_proc_addr,
+ device->vtbl_storage)) {
+ DestroyDevice(device);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ PFN_vkCreateDevice layer_createDevice =
+ reinterpret_cast<PFN_vkCreateDevice>(
+ device->vtbl_storage.GetDeviceProcAddr(drv_device,
+ "vkCreateDevice"));
+ layer_createDevice(pdev, create_info, &drv_device);
*out_device = drv_device;
return VK_SUCCESS;
@@ -386,12 +672,24 @@
.GetPhysicalDeviceExtensionProperties = GetPhysicalDeviceExtensionPropertiesBottom,
.GetPhysicalDeviceLayerProperties = GetPhysicalDeviceLayerPropertiesBottom,
.GetPhysicalDeviceSparseImageFormatProperties = GetPhysicalDeviceSparseImageFormatPropertiesBottom,
+ .GetPhysicalDeviceSurfaceSupportKHR = GetPhysicalDeviceSurfaceSupportKHR,
// clang-format on
};
+VkResult Noop(...) {
+ return VK_SUCCESS;
+}
+
PFN_vkVoidFunction GetInstanceProcAddrBottom(VkInstance, const char* name) {
- // The bottom GetInstanceProcAddr is only called by the innermost layer,
- // when there is one, when it initializes its own dispatch table.
+ // TODO: Possibly move this into the instance table
+ // TODO: Possibly register the callbacks in the loader
+ if (strcmp(name, "vkDbgCreateMsgCallback") == 0 ||
+ strcmp(name, "vkDbgDestroyMsgCallback") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(Noop);
+ }
+ if (strcmp(name, "vkCreateInstance") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(CreateInstanceBottom);
+ }
return GetSpecificInstanceProcAddr(&kBottomInstanceFunctions, name);
}
@@ -453,13 +751,141 @@
instance->vtbl_storage = kBottomInstanceFunctions;
instance->vtbl_storage.instance = instance;
+ instance->message = VK_NULL_HANDLE;
- // TODO: Insert enabled layers into instance->dispatch_vtbl here.
+ // Scan layers
+ UnorderedMap<String, SharedLibraryHandle> layers(
+ CallbackAllocator<std::pair<String, SharedLibraryHandle> >(
+ instance->alloc));
+ CallbackAllocator<char> string_allocator(instance->alloc);
+ String dir_name("/data/local/tmp/vulkan/", string_allocator);
+ FindLayersInDirectory(*instance, layers, dir_name);
+ const std::string& path = LoaderData::GetInstance().layer_path;
+ dir_name.assign(path.c_str(), path.size());
+ dir_name.append("/");
+ FindLayersInDirectory(*instance, layers, dir_name);
- // TODO: We'll want to call CreateInstance through the dispatch table
- // instead of calling the loader's terminator
+ // Load layers
+ {
+ char layer_prop[PROPERTY_VALUE_MAX];
+ property_get("debug.vulkan.layers", layer_prop, "");
+ String layer_name(string_allocator);
+ String layer_prop_str(layer_prop, string_allocator);
+ size_t end, start = 0;
+ while ((end = layer_prop_str.find(':', start)) != std::string::npos) {
+ layer_name = layer_prop_str.substr(start, end - start);
+ auto element = layers.find(layer_name);
+ if (element != layers.end()) {
+ LoadLayer(instance, layer_name, element->second);
+ layers.erase(element);
+ }
+ start = end + 1;
+ }
+ InstanceLayersPair instance_layers_pair = {.instance = instance,
+ .layers = &layers};
+ property_list(LoadLayerFromProperty,
+ static_cast<void*>(&instance_layers_pair));
+ }
+ for (uint32_t i = 0; i < create_info->layerCount; ++i) {
+ String layer_name(create_info->ppEnabledLayerNames[i],
+ string_allocator);
+ auto element = layers.find(layer_name);
+ if (element != layers.end()) {
+ LoadLayer(instance, layer_name, element->second);
+ layers.erase(element);
+ }
+ }
+ for (auto& layer : layers) {
+ dlclose(layer.second);
+ }
+
+ void* base_object = static_cast<void*>(instance);
+ void* next_object = base_object;
+ VkLayerLinkedListElem* next_element;
+ PFN_vkGetInstanceProcAddr next_get_proc_addr =
+ kBottomInstanceFunctions.GetInstanceProcAddr;
+ Vector<VkLayerLinkedListElem> elem_list(
+ instance->active_layers.size(),
+ CallbackAllocator<VkLayerLinkedListElem>(instance->alloc));
+
+ for (size_t i = elem_list.size(); i > 0; i--) {
+ size_t idx = i - 1;
+ next_element = &elem_list[idx];
+ next_element->get_proc_addr =
+ reinterpret_cast<PFN_vkGetProcAddr>(next_get_proc_addr);
+ next_element->base_object = base_object;
+ next_element->next_element = next_object;
+ next_object = static_cast<void*>(next_element);
+
+ auto& name_libhandle_pair = instance->active_layers[idx];
+ next_get_proc_addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
+ dlsym(name_libhandle_pair.second,
+ (name_libhandle_pair.first + "GetInstanceProcAddr").c_str()));
+ if (!next_get_proc_addr) {
+ next_get_proc_addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
+ dlsym(name_libhandle_pair.second, "vkGetInstanceProcAddr"));
+ if (!next_get_proc_addr) {
+ ALOGE("Cannot find vkGetInstanceProcAddr for %s, error is %s",
+ name_libhandle_pair.first.c_str(), dlerror());
+ next_object = next_element->next_element;
+ next_get_proc_addr =
+ reinterpret_cast<PFN_vkGetInstanceProcAddr>(
+ next_element->get_proc_addr);
+ }
+ }
+ }
+
+ if (!LoadInstanceVtbl(static_cast<VkInstance>(base_object),
+ static_cast<VkInstance>(next_object),
+ next_get_proc_addr, instance->vtbl_storage)) {
+ DestroyInstanceBottom(instance);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ // Force enable callback extension if required
+ bool enable_callback =
+ property_get_bool("debug.vulkan.enable_layer_callback", false);
+ bool enable_logging = enable_callback;
+ const char* callback_name = "DEBUG_REPORT";
+ if (enable_callback) {
+ for (uint32_t i = 0; i < create_info->extensionCount; ++i) {
+ if (!strcmp(callback_name,
+ create_info->ppEnabledExtensionNames[i])) {
+ enable_callback = false;
+ break;
+ }
+ }
+ }
+ if (enable_callback) {
+ uint32_t extension_count = local_create_info.extensionCount;
+ local_create_info.extensionCount++;
+ void* mem = instance->alloc->pfnAlloc(
+ instance->alloc->pUserData,
+ local_create_info.extensionCount * sizeof(char*), alignof(char*),
+ VK_SYSTEM_ALLOC_TYPE_INTERNAL);
+ if (mem) {
+ const char** enabled_extensions = static_cast<const char**>(mem);
+ for (uint32_t i = 0; i < extension_count; ++i) {
+ enabled_extensions[i] =
+ local_create_info.ppEnabledExtensionNames[i];
+ }
+ enabled_extensions[extension_count] = callback_name;
+ local_create_info.ppEnabledExtensionNames = enabled_extensions;
+ } else {
+ ALOGW("DEBUG_REPORT extension cannot be enabled!");
+ enable_callback = false;
+ local_create_info.extensionCount--;
+ }
+ }
+
*out_instance = instance;
- result = CreateInstanceBottom(create_info, out_instance);
+ result = instance->vtbl_storage.CreateInstance(create_info, out_instance);
+ if (enable_callback) {
+ const char* const* enabled_extensions =
+ local_create_info.ppEnabledExtensionNames;
+ instance->alloc->pfnFree(instance->alloc->pUserData,
+ const_cast<char**>(enabled_extensions));
+ }
if (result <= 0) {
// For every layer, including the loader top and bottom layers:
// - If a call to the next CreateInstance fails, the layer must clean
@@ -475,12 +901,29 @@
// already gone at this point. Nothing to do.
}
+ if (enable_logging) {
+ PFN_vkDbgCreateMsgCallback DebugCreateMessageCallback;
+ DebugCreateMessageCallback = reinterpret_cast<PFN_vkDbgCreateMsgCallback>(
+ vkGetInstanceProcAddr(instance, "vkDbgCreateMsgCallback"));
+ DebugCreateMessageCallback(instance,
+ VK_DBG_REPORT_ERROR_BIT | VK_DBG_REPORT_WARN_BIT,
+ LogDebugMessageCallback, NULL, &instance->message);
+ }
+
return result;
}
PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
if (!instance)
return GetGlobalInstanceProcAddr(name);
+ // TODO: Possibly move this into the instance table
+ if (strcmp(name, "vkDbgCreateMsgCallback") == 0 ||
+ strcmp(name, "vkDbgDestroyMsgCallback") == 0) {
+ if (!instance->vtbl)
+ return NULL;
+ PFN_vkGetInstanceProcAddr gpa = instance->vtbl->GetInstanceProcAddr;
+ return reinterpret_cast<PFN_vkVoidFunction>(gpa(instance, name));
+ }
// For special-case functions we always return the loader entry
if (strcmp(name, "vkGetInstanceProcAddr") == 0 ||
strcmp(name, "vkGetDeviceProcAddr") == 0) {
@@ -492,6 +935,9 @@
PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) {
if (!device)
return GetGlobalDeviceProcAddr(name);
+ if (strcmp(name, "vkGetDeviceProcAddr") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr);
+ }
// For special-case functions we always return the loader entry
if (strcmp(name, "vkGetDeviceQueue") == 0 ||
strcmp(name, "vkCreateCommandBuffer") == 0 ||
@@ -551,4 +997,37 @@
return VK_SUCCESS;
}
+void* AllocDeviceMem(VkDevice device,
+ size_t size,
+ size_t align,
+ VkSystemAllocType type) {
+ const VkAllocCallbacks* alloc_cb =
+ static_cast<Device*>(GetVtbl(device)->device)->alloc;
+ return alloc_cb->pfnAlloc(alloc_cb->pUserData, size, align, type);
+}
+
+void FreeDeviceMem(VkDevice device, void* ptr) {
+ const VkAllocCallbacks* alloc_cb =
+ static_cast<Device*>(GetVtbl(device)->device)->alloc;
+ alloc_cb->pfnFree(alloc_cb->pUserData, ptr);
+}
+
+const DeviceVtbl& GetDriverVtbl(VkDevice device) {
+ // TODO(jessehall): This actually returns the API-level vtbl for the
+ // device, not the driver entry points. Given the current use -- getting
+ // the driver's private swapchain-related functions -- that works, but is
+ // misleading and likely to cause bugs. Fix as part of separating the
+ // loader->driver interface from the app->loader interface.
+ return static_cast<Device*>(GetVtbl(device)->device)->vtbl_storage;
+}
+
+const DeviceVtbl& GetDriverVtbl(VkQueue queue) {
+ // TODO(jessehall): This actually returns the API-level vtbl for the
+ // device, not the driver entry points. Given the current use -- getting
+ // the driver's private swapchain-related functions -- that works, but is
+ // misleading and likely to cause bugs. Fix as part of separating the
+ // loader->driver interface from the app->loader interface.
+ return static_cast<Device*>(GetVtbl(queue)->device)->vtbl_storage;
+}
+
} // namespace vulkan
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index fad92a7..5933eb2 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -1,11 +1,36 @@
+/*
+ * 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 LIBVULKAN_LOADER_H
#define LIBVULKAN_LOADER_H 1
#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;
@@ -27,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
};
@@ -169,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;
};
// -----------------------------------------------------------------------------
@@ -192,6 +234,14 @@
VkCmdBuffer* out_cmdbuf);
VkResult DestroyDevice(VkDevice drv_device);
+void* AllocDeviceMem(VkDevice device,
+ size_t size,
+ size_t align,
+ VkSystemAllocType type);
+void FreeDeviceMem(VkDevice device, void* ptr);
+const DeviceVtbl& GetDriverVtbl(VkDevice device);
+const DeviceVtbl& GetDriverVtbl(VkQueue queue);
+
// -----------------------------------------------------------------------------
// get_proc_addr.cpp
@@ -203,12 +253,48 @@
const char* name);
bool LoadInstanceVtbl(VkInstance instance,
+ VkInstance next_instance,
PFN_vkGetInstanceProcAddr get_proc_addr,
InstanceVtbl& vtbl);
bool LoadDeviceVtbl(VkDevice device,
+ VkDevice next_device,
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_handle);
+VkResult DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle);
+VkResult GetSwapchainImagesKHR(VkDevice device,
+ VkSwapchainKHR swapchain_handle,
+ uint32_t* count,
+ VkImage* images);
+VkResult AcquireNextImageKHR(VkDevice device,
+ VkSwapchainKHR swapchain_handle,
+ 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..af3d585
--- /dev/null
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -0,0 +1,633 @@
+/*
+ * 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.
+ */
+
+// #define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <memory>
+
+#include <gui/BufferQueue.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+#include "loader.h"
+
+using namespace vulkan;
+
+namespace {
+
+// ----------------------------------------------------------------------------
+// These functions/classes form an adaptor that allows objects to be refcounted
+// by both android::sp<> and std::shared_ptr<> simultaneously, and delegates
+// allocation of the shared_ptr<> control structure to VkAllocCallbacks. The
+// platform holds a reference to the ANativeWindow using its embedded reference
+// count, and the ANativeWindow implementation holds references to the
+// ANativeWindowBuffers using their embedded reference counts, so the
+// shared_ptr *must* cooperate with these and hold at least one reference to
+// the object using the embedded reference count.
+
+template <typename T>
+struct NativeBaseDeleter {
+ void operator()(T* obj) { obj->common.decRef(&obj->common); }
+};
+
+template <typename T>
+class VulkanAllocator {
+ public:
+ typedef T value_type;
+
+ explicit VulkanAllocator(VkDevice device) : device_(device) {}
+
+ template <typename U>
+ explicit VulkanAllocator(const VulkanAllocator<U>& other)
+ : device_(other.device_) {}
+
+ T* allocate(size_t n) const {
+ return static_cast<T*>(AllocDeviceMem(
+ device_, n * sizeof(T), alignof(T), VK_SYSTEM_ALLOC_TYPE_INTERNAL));
+ }
+ void deallocate(T* p, size_t) const { return FreeDeviceMem(device_, p); }
+
+ private:
+ template <typename U>
+ friend class VulkanAllocator;
+ VkDevice device_;
+};
+
+template <typename T>
+std::shared_ptr<T> InitSharedPtr(VkDevice device, T* obj) {
+ obj->common.incRef(&obj->common);
+ return std::shared_ptr<T>(obj, NativeBaseDeleter<T>(),
+ VulkanAllocator<T>(device));
+}
+
+// ----------------------------------------------------------------------------
+
+struct Swapchain {
+ Swapchain(std::shared_ptr<ANativeWindow> window_, uint32_t num_images_)
+ : window(window_), num_images(num_images_) {}
+
+ std::shared_ptr<ANativeWindow> window;
+ uint32_t num_images;
+
+ struct Image {
+ Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
+ VkImage image;
+ std::shared_ptr<ANativeWindowBuffer> buffer;
+ // The fence is only valid when the buffer is dequeued, and should be
+ // -1 any other time. When valid, we own the fd, and must ensure it is
+ // closed: either by closing it explicitly when queueing the buffer,
+ // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
+ int dequeue_fence;
+ bool dequeued;
+ } images[android::BufferQueue::NUM_BUFFER_SLOTS];
+};
+
+VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
+ return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
+}
+
+Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
+ return reinterpret_cast<Swapchain*>(handle.handle);
+}
+
+} // anonymous namespace
+
+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;
+}
+
+VkResult GetSurfacePropertiesKHR(VkDevice /*device*/,
+ const VkSurfaceDescriptionKHR* surface_desc,
+ VkSurfacePropertiesKHR* properties) {
+ const VkSurfaceDescriptionWindowKHR* window_desc =
+ reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(surface_desc);
+ ANativeWindow* window =
+ static_cast<ANativeWindow*>(window_desc->pPlatformWindow);
+
+ int err;
+
+ // TODO(jessehall): Currently the window must be connected for several
+ // queries -- including default dimensions -- to work, since Surface caches
+ // the queried values at connect() and queueBuffer(), and query() returns
+ // those cached values.
+ //
+ // The proposed refactoring to create a VkSurface object (bug 14596) will
+ // give us a place to connect once per window. If that doesn't end up
+ // happening, we'll probably need to maintain an internal list of windows
+ // that have swapchains created for them, search that list here, and
+ // only temporarily connect if the window doesn't have a swapchain.
+
+ bool disconnect = true;
+ err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (err == -EINVAL) {
+ // This is returned if the window is already connected, among other
+ // things. We'll just assume we're already connected and charge ahead.
+ // See TODO above, this is not cool.
+ ALOGW(
+ "vkGetSurfacePropertiesKHR: native_window_api_connect returned "
+ "-EINVAL, assuming already connected");
+ err = 0;
+ disconnect = false;
+ } else if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ return VK_ERROR_UNKNOWN;
+ }
+
+ int width, height;
+ err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
+ if (err != 0) {
+ ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+ strerror(-err), err);
+ if (disconnect)
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ return VK_ERROR_UNKNOWN;
+ }
+ err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
+ if (err != 0) {
+ ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+ strerror(-err), err);
+ if (disconnect)
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ return VK_ERROR_UNKNOWN;
+ }
+
+ if (disconnect)
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+
+ properties->currentExtent = VkExtent2D{width, height};
+
+ // TODO(jessehall): Figure out what the min/max values should be.
+ properties->minImageCount = 2;
+ properties->maxImageCount = 3;
+
+ // TODO(jessehall): Figure out what the max extent should be. Maximum
+ // texture dimension maybe?
+ properties->minImageExtent = VkExtent2D{1, 1};
+ properties->maxImageExtent = VkExtent2D{4096, 4096};
+
+ // TODO(jessehall): We can support all transforms, fix this once
+ // implemented.
+ properties->supportedTransforms = VK_SURFACE_TRANSFORM_NONE_BIT_KHR;
+
+ // TODO(jessehall): Implement based on NATIVE_WINDOW_TRANSFORM_HINT.
+ properties->currentTransform = VK_SURFACE_TRANSFORM_NONE_KHR;
+
+ properties->maxImageArraySize = 1;
+
+ // TODO(jessehall): I think these are right, but haven't thought hard about
+ // it. Do we need to query the driver for support of any of these?
+ // Currently not included:
+ // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
+ // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
+ // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
+ properties->supportedUsageFlags =
+ VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
+
+ return VK_SUCCESS;
+}
+
+VkResult GetSurfaceFormatsKHR(VkDevice /*device*/,
+ const VkSurfaceDescriptionKHR* /*surface_desc*/,
+ uint32_t* count,
+ VkSurfaceFormatKHR* formats) {
+ // TODO(jessehall): Fill out the set of supported formats. Open question
+ // whether we should query the driver for support -- how does it know what
+ // the consumer can support? Should we support formats that don't
+ // correspond to gralloc formats?
+
+ const VkSurfaceFormatKHR kFormats[] = {
+ {VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
+ {VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
+ };
+ const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
+
+ VkResult result = VK_SUCCESS;
+ if (formats) {
+ if (*count < kNumFormats)
+ result = VK_INCOMPLETE;
+ std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
+ }
+ *count = kNumFormats;
+ return result;
+}
+
+VkResult GetSurfacePresentModesKHR(
+ VkDevice /*device*/,
+ const VkSurfaceDescriptionKHR* /*surface_desc*/,
+ uint32_t* count,
+ VkPresentModeKHR* modes) {
+ const VkPresentModeKHR kModes[] = {
+ VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
+ };
+ const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
+
+ VkResult result = VK_SUCCESS;
+ if (modes) {
+ if (*count < kNumModes)
+ result = VK_INCOMPLETE;
+ std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
+ }
+ *count = kNumModes;
+ return result;
+}
+
+VkResult CreateSwapchainKHR(VkDevice device,
+ const VkSwapchainCreateInfoKHR* create_info,
+ VkSwapchainKHR* swapchain_handle) {
+ int err;
+ VkResult result = VK_SUCCESS;
+
+ ALOGV_IF(create_info->imageArraySize != 1,
+ "Swapchain imageArraySize (%u) != 1 not supported",
+ create_info->imageArraySize);
+
+ ALOGE_IF(create_info->imageFormat != VK_FORMAT_R8G8B8A8_UNORM,
+ "swapchain formats other than R8G8B8A8_UNORM not yet implemented");
+ ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
+ "color spaces other than SRGB_NONLINEAR not yet implemented");
+ ALOGE_IF(create_info->oldSwapchain,
+ "swapchain re-creation not yet implemented");
+ ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_NONE_KHR,
+ "swapchain preTransform not yet implemented");
+ ALOGE_IF(create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR,
+ "present modes other than FIFO are not yet implemented");
+
+ // -- Configure the native window --
+ // Failure paths from here on need to disconnect the window.
+
+ std::shared_ptr<ANativeWindow> window = InitSharedPtr(
+ device, static_cast<ANativeWindow*>(
+ reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(
+ create_info->pSurfaceDescription)
+ ->pPlatformWindow));
+
+ // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
+ err = native_window_api_connect(window.get(), NATIVE_WINDOW_API_EGL);
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
+ err);
+ return VK_ERROR_UNKNOWN;
+ }
+
+ err = native_window_set_buffers_dimensions(window.get(),
+ create_info->imageExtent.width,
+ create_info->imageExtent.height);
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
+ create_info->imageExtent.width, create_info->imageExtent.height,
+ strerror(-err), err);
+ native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
+ return VK_ERROR_UNKNOWN;
+ }
+
+ uint32_t min_undequeued_buffers;
+ err = window->query(window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ reinterpret_cast<int*>(&min_undequeued_buffers));
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("window->query failed: %s (%d)", strerror(-err), err);
+ native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
+ return VK_ERROR_UNKNOWN;
+ }
+ uint32_t num_images =
+ (create_info->minImageCount - 1) + min_undequeued_buffers;
+ err = native_window_set_buffer_count(window.get(), num_images);
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
+ err);
+ native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
+ return VK_ERROR_UNKNOWN;
+ }
+
+ // TODO(jessehall): Do we need to call modify native_window_set_usage()
+ // based on create_info->imageUsageFlags?
+
+ // -- Allocate our Swapchain object --
+ // After this point, we must deallocate the swapchain on error.
+
+ void* mem = AllocDeviceMem(device, sizeof(Swapchain), alignof(Swapchain),
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (!mem) {
+ native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ Swapchain* swapchain = new (mem) Swapchain(window, num_images);
+
+ // -- Dequeue all buffers and create a VkImage for each --
+ // Any failures during or after this must cancel the dequeued buffers.
+
+ VkNativeBufferANDROID image_native_buffer = {
+// TODO(jessehall): Figure out how to make extension headers not horrible.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+ .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
+#pragma clang diagnostic pop
+ .pNext = nullptr,
+ };
+ VkImageCreateInfo image_create = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+ .pNext = &image_native_buffer,
+ .imageType = VK_IMAGE_TYPE_2D,
+ .format = VK_FORMAT_R8G8B8A8_UNORM, // TODO(jessehall)
+ .extent = {0, 0, 1},
+ .mipLevels = 1,
+ .arraySize = 1,
+ .samples = 1,
+ .tiling = VK_IMAGE_TILING_OPTIMAL,
+ .usage = create_info->imageUsageFlags,
+ .flags = 0,
+ .sharingMode = create_info->sharingMode,
+ .queueFamilyCount = create_info->queueFamilyCount,
+ .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
+ };
+
+ const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
+ for (uint32_t i = 0; i < num_images; i++) {
+ Swapchain::Image& img = swapchain->images[i];
+
+ ANativeWindowBuffer* buffer;
+ err = window->dequeueBuffer(window.get(), &buffer, &img.dequeue_fence);
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate
+ // possible errors and translate them to valid Vulkan result codes?
+ ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
+ result = VK_ERROR_UNKNOWN;
+ break;
+ }
+ img.buffer = InitSharedPtr(device, buffer);
+ img.dequeued = true;
+
+ image_create.extent =
+ VkExtent3D{img.buffer->width, img.buffer->height, 1};
+ image_native_buffer.handle = img.buffer->handle;
+ image_native_buffer.stride = img.buffer->stride;
+ image_native_buffer.format = img.buffer->format;
+ image_native_buffer.usage = img.buffer->usage;
+
+ result = driver_vtbl.CreateImage(device, &image_create, &img.image);
+ if (result != VK_SUCCESS) {
+ ALOGD("vkCreateImage w/ native buffer failed: %u", result);
+ break;
+ }
+ }
+
+ // -- Cancel all buffers, returning them to the queue --
+ // If an error occurred before, also destroy the VkImage and release the
+ // buffer reference. Otherwise, we retain a strong reference to the buffer.
+ //
+ // TODO(jessehall): The error path here is the same as DestroySwapchain,
+ // but not the non-error path. Should refactor/unify.
+ for (uint32_t i = 0; i < num_images; i++) {
+ Swapchain::Image& img = swapchain->images[i];
+ if (img.dequeued) {
+ window->cancelBuffer(window.get(), img.buffer.get(),
+ img.dequeue_fence);
+ img.dequeue_fence = -1;
+ img.dequeued = false;
+ }
+ if (result != VK_SUCCESS) {
+ if (img.image)
+ driver_vtbl.DestroyImage(device, img.image);
+ }
+ }
+
+ if (result != VK_SUCCESS) {
+ native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
+ swapchain->~Swapchain();
+ FreeDeviceMem(device, swapchain);
+ return result;
+ }
+
+ *swapchain_handle = HandleFromSwapchain(swapchain);
+ return VK_SUCCESS;
+}
+
+VkResult DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle) {
+ const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
+ Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
+ const std::shared_ptr<ANativeWindow>& window = swapchain->window;
+
+ for (uint32_t i = 0; i < swapchain->num_images; i++) {
+ Swapchain::Image& img = swapchain->images[i];
+ if (img.dequeued) {
+ window->cancelBuffer(window.get(), img.buffer.get(),
+ img.dequeue_fence);
+ img.dequeue_fence = -1;
+ img.dequeued = false;
+ }
+ if (img.image) {
+ driver_vtbl.DestroyImage(device, img.image);
+ }
+ }
+
+ native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
+ swapchain->~Swapchain();
+ FreeDeviceMem(device, swapchain);
+
+ return VK_SUCCESS;
+}
+
+VkResult GetSwapchainImagesKHR(VkDevice,
+ VkSwapchainKHR swapchain_handle,
+ uint32_t* count,
+ VkImage* images) {
+ Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
+ VkResult result = VK_SUCCESS;
+ if (images) {
+ uint32_t n = swapchain.num_images;
+ if (*count < swapchain.num_images) {
+ n = *count;
+ result = VK_INCOMPLETE;
+ }
+ for (uint32_t i = 0; i < n; i++)
+ images[i] = swapchain.images[i].image;
+ }
+ *count = swapchain.num_images;
+ return result;
+}
+
+VkResult AcquireNextImageKHR(VkDevice device,
+ VkSwapchainKHR swapchain_handle,
+ uint64_t timeout,
+ VkSemaphore semaphore,
+ uint32_t* image_index) {
+ Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
+ VkResult result;
+ int err;
+
+ ALOGW_IF(
+ timeout != UINT64_MAX,
+ "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
+
+ ANativeWindowBuffer* buffer;
+ int fence;
+ err = swapchain.window->dequeueBuffer(swapchain.window.get(), &buffer,
+ &fence);
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
+ return VK_ERROR_UNKNOWN;
+ }
+
+ uint32_t idx;
+ for (idx = 0; idx < swapchain.num_images; idx++) {
+ if (swapchain.images[idx].buffer.get() == buffer) {
+ swapchain.images[idx].dequeued = true;
+ swapchain.images[idx].dequeue_fence = fence;
+ break;
+ }
+ }
+ if (idx == swapchain.num_images) {
+ ALOGE("dequeueBuffer returned unrecognized buffer");
+ swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence);
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+ return VK_ERROR_OUT_OF_DATE_KHR;
+#pragma clang diagnostic pop
+ }
+
+ int fence_clone = -1;
+ if (fence != -1) {
+ fence_clone = dup(fence);
+ if (fence_clone == -1) {
+ ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
+ strerror(errno), errno);
+ sync_wait(fence, -1 /* forever */);
+ }
+ }
+
+ const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
+ result =
+ driver_vtbl.ImportNativeFenceANDROID(device, semaphore, fence_clone);
+ if (result != VK_SUCCESS) {
+ // NOTE: we're relying on ImportNativeFenceANDROID to close
+ // fence_clone, even if the call fails. We could close it ourselves on
+ // failure, but that would create a race condition if the driver closes
+ // it on a failure path. We must assume one of: the driver *always*
+ // closes it even on failure, or *never* closes it on failure.
+ swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence);
+ swapchain.images[idx].dequeued = false;
+ swapchain.images[idx].dequeue_fence = -1;
+ return result;
+ }
+
+ *image_index = idx;
+ return VK_SUCCESS;
+}
+
+VkResult QueuePresentKHR(VkQueue queue, VkPresentInfoKHR* present_info) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+ ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
+ present_info->sType);
+#pragma clang diagnostic pop
+ ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
+
+ const DeviceVtbl& driver_vtbl = GetDriverVtbl(queue);
+ VkResult final_result = VK_SUCCESS;
+ for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
+ Swapchain& swapchain =
+ *SwapchainFromHandle(present_info->swapchains[sc]);
+ uint32_t image_idx = present_info->imageIndices[sc];
+ VkResult result;
+ int err;
+
+ if (image_idx >= swapchain.num_images ||
+ !swapchain.images[image_idx].dequeued) {
+ ALOGE(
+ "invalid image index or image not acquired: swapchain=%u "
+ "index=%u",
+ sc, image_idx);
+ final_result = VK_ERROR_INVALID_VALUE;
+ continue;
+ }
+ Swapchain::Image& img = swapchain.images[image_idx];
+
+ int fence = -1;
+ result = driver_vtbl.QueueSignalNativeFenceANDROID(queue, &fence);
+ if (result != VK_SUCCESS) {
+ ALOGE("vkQueueSignalNativeFenceANDROID failed: %d", result);
+ if (final_result == VK_SUCCESS)
+ final_result = result;
+ // TODO(jessehall): What happens to the buffer here? Does the app
+ // still own it or not, i.e. should we cancel the buffer? Hard to
+ // do correctly without synchronizing, though I guess we could wait
+ // for the queue to idle.
+ continue;
+ }
+
+ err = swapchain.window->queueBuffer(swapchain.window.get(),
+ img.buffer.get(), fence);
+ if (err != 0) {
+ // TODO(jessehall): What now? We should probably cancel the buffer,
+ // I guess?
+ ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
+ if (final_result == VK_SUCCESS)
+ final_result = VK_ERROR_UNKNOWN;
+ continue;
+ }
+
+ if (img.dequeue_fence != -1) {
+ close(img.dequeue_fence);
+ img.dequeue_fence = -1;
+ }
+ img.dequeued = false;
+ }
+
+ return final_result;
+}
+
+} // namespace vulkan
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/vulkan/libvulkan/vulkan_loader_data.cpp
new file mode 100644
index 0000000..a6a0295
--- /dev/null
+++ b/vulkan/libvulkan/vulkan_loader_data.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 <vulkan/vulkan_loader_data.h>
+
+using namespace vulkan;
+
+LoaderData& LoaderData::GetInstance() {
+ static LoaderData loader_data;
+ return loader_data;
+}
diff --git a/vulkan/nulldrv/Android.mk b/vulkan/nulldrv/Android.mk
index a81bcd6..b98ec20 100644
--- a/vulkan/nulldrv/Android.mk
+++ b/vulkan/nulldrv/Android.mk
@@ -1,3 +1,17 @@
+# 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.
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index ad7011f..8f65156 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -1,8 +1,25 @@
+/*
+ * 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 <hardware/hwvulkan.h>
#include <array>
-#include <string.h>
#include <algorithm>
+#include <inttypes.h>
+#include <string.h>
// #define LOG_NDEBUG 0
#include <log/log.h>
@@ -77,6 +94,9 @@
};
} // namespace HandleType
uint64_t AllocHandle(VkDevice device, HandleType::Enum type);
+
+const VkDeviceSize kMaxDeviceMemory = VkDeviceSize(INTPTR_MAX) + 1;
+
} // anonymous namespace
struct VkDevice_T {
@@ -100,13 +120,13 @@
__attribute__((visibility("default"))) hwvulkan_module_t HAL_MODULE_INFO_SYM = {
.common =
{
- .tag = HARDWARE_MODULE_TAG,
- .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1,
- .hal_api_version = HARDWARE_HAL_API_VERSION,
- .id = HWVULKAN_HARDWARE_MODULE_ID,
- .name = "Null Vulkan Driver",
- .author = "The Android Open Source Project",
- .methods = &nulldrv_module_methods,
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = HWVULKAN_HARDWARE_MODULE_ID,
+ .name = "Null Vulkan Driver",
+ .author = "The Android Open Source Project",
+ .methods = &nulldrv_module_methods,
},
};
#pragma clang diagnostic pop
@@ -117,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),
@@ -140,10 +165,10 @@
hwvulkan_device_t nulldrv_device = {
.common =
{
- .tag = HARDWARE_DEVICE_TAG,
- .version = HWVULKAN_DEVICE_API_VERSION_0_1,
- .module = &HAL_MODULE_INFO_SYM.common,
- .close = CloseDevice,
+ .tag = HARDWARE_DEVICE_TAG,
+ .version = HWVULKAN_DEVICE_API_VERSION_0_1,
+ .module = &HAL_MODULE_INFO_SYM.common,
+ .close = CloseDevice,
},
.GetGlobalExtensionProperties = GetGlobalExtensionProperties,
.CreateInstance = CreateInstance,
@@ -169,8 +194,7 @@
uint64_t AllocHandle(VkDevice device, HandleType::Enum type) {
const uint64_t kHandleMask = (UINT64_C(1) << 56) - 1;
ALOGE_IF(device->next_handle[type] == kHandleMask,
- "non-dispatchable handles of type=%u are about to overflow",
- type);
+ "non-dispatchable handles of type=%u are about to overflow", type);
return (UINT64_C(1) << 63) | ((uint64_t(type) & 0x7) << 56) |
(device->next_handle[type]++ & kHandleMask);
}
@@ -212,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;
}
// -----------------------------------------------------------------------------
@@ -256,8 +288,7 @@
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
properties->memoryTypes[0].heapIndex = 0;
properties->memoryHeapCount = 1;
- properties->memoryHeaps[0].size =
- INTPTR_MAX; // TODO: do something smarter?
+ properties->memoryHeaps[0].size = kMaxDeviceMemory;
properties->memoryHeaps[0].flags = VK_MEMORY_HEAP_HOST_LOCAL;
return VK_SUCCESS;
}
@@ -385,6 +416,11 @@
VkResult CreateBuffer(VkDevice device,
const VkBufferCreateInfo* create_info,
VkBuffer* buffer_handle) {
+ ALOGW_IF(create_info->size > kMaxDeviceMemory,
+ "CreateBuffer: requested size 0x%" PRIx64
+ " exceeds max device memory size 0x%" PRIx64,
+ create_info->size, kMaxDeviceMemory);
+
const VkAllocCallbacks* alloc = device->instance->alloc;
Buffer* buffer = static_cast<Buffer*>(
alloc->pfnAlloc(alloc->pUserData, sizeof(Buffer), alignof(Buffer),
@@ -414,6 +450,66 @@
}
// -----------------------------------------------------------------------------
+// Image
+
+struct Image {
+ typedef VkImage HandleType;
+ VkDeviceSize size;
+};
+template <>
+struct HandleTraits<VkImage> {
+ typedef Image* PointerType;
+};
+
+VkResult CreateImage(VkDevice device,
+ const VkImageCreateInfo* create_info,
+ VkImage* image_handle) {
+ if (create_info->imageType != VK_IMAGE_TYPE_2D ||
+ create_info->format != VK_FORMAT_R8G8B8A8_UNORM ||
+ create_info->mipLevels != 1) {
+ ALOGE("CreateImage: not yet implemented: type=%d format=%d mips=%u",
+ create_info->imageType, create_info->format,
+ create_info->mipLevels);
+ return VK_ERROR_UNAVAILABLE;
+ }
+
+ VkDeviceSize size =
+ VkDeviceSize(create_info->extent.width * create_info->extent.height) *
+ create_info->arraySize * create_info->samples * 4u;
+ ALOGW_IF(size > kMaxDeviceMemory,
+ "CreateImage: image size 0x%" PRIx64
+ " exceeds max device memory size 0x%" PRIx64,
+ size, kMaxDeviceMemory);
+
+ const VkAllocCallbacks* alloc = device->instance->alloc;
+ Image* image = static_cast<Image*>(
+ alloc->pfnAlloc(alloc->pUserData, sizeof(Image), alignof(Image),
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT));
+ if (!image)
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ image->size = size;
+ *image_handle = GetHandleToObject(image);
+ return VK_SUCCESS;
+}
+
+VkResult GetImageMemoryRequirements(VkDevice,
+ VkImage image_handle,
+ VkMemoryRequirements* requirements) {
+ Image* image = GetObjectFromHandle(image_handle);
+ requirements->size = image->size;
+ requirements->alignment = 16; // allow fast Neon/SSE memcpy
+ requirements->memoryTypeBits = 0x1;
+ return VK_SUCCESS;
+}
+
+VkResult DestroyImage(VkDevice device, VkImage image_handle) {
+ const VkAllocCallbacks* alloc = device->instance->alloc;
+ Image* image = GetObjectFromHandle(image_handle);
+ alloc->pfnFree(alloc->pUserData, image);
+ return VK_SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
// No-op types
VkResult CreateAttachmentView(VkDevice device,
@@ -599,6 +695,16 @@
return VK_SUCCESS;
}
+VkResult ImportNativeFenceANDROID(VkDevice, VkSemaphore, int fence) {
+ close(fence);
+ return VK_SUCCESS;
+}
+
+VkResult QueueSignalNativeFenceANDROID(VkQueue, int* fence) {
+ *fence = -1;
+ return VK_SUCCESS;
+}
+
// -----------------------------------------------------------------------------
// No-op entrypoints
@@ -688,13 +794,7 @@
return VK_SUCCESS;
}
-VkResult GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements) {
- ALOGV("TODO: vk%s", __FUNCTION__);
- return VK_SUCCESS;
-}
-
VkResult BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset) {
- ALOGV("TODO: vk%s", __FUNCTION__);
return VK_SUCCESS;
}
@@ -750,7 +850,6 @@
}
VkResult QueueWaitSemaphore(VkQueue queue, VkSemaphore semaphore) {
- ALOGV("TODO: vk%s", __FUNCTION__);
return VK_SUCCESS;
}
@@ -786,16 +885,6 @@
return VK_SUCCESS;
}
-VkResult CreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage) {
- ALOGV("TODO: vk%s", __FUNCTION__);
- return VK_SUCCESS;
-}
-
-VkResult DestroyImage(VkDevice device, VkImage image) {
- ALOGV("TODO: vk%s", __FUNCTION__);
- return VK_SUCCESS;
-}
-
VkResult GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) {
ALOGV("TODO: vk%s", __FUNCTION__);
return VK_SUCCESS;
diff --git a/vulkan/nulldrv/null_driver.h b/vulkan/nulldrv/null_driver.h
index f9208f9..6bfbda5 100644
--- a/vulkan/nulldrv/null_driver.h
+++ b/vulkan/nulldrv/null_driver.h
@@ -1,8 +1,25 @@
+/*
+ * 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 NULLDRV_NULL_DRIVER_H
#define NULLDRV_NULL_DRIVER_H 1
#define VK_PROTOTYPES
#include <vulkan/vulkan.h>
+#include <vulkan/vk_ext_android_native_buffer.h>
namespace null_driver {
@@ -161,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
diff --git a/vulkan/nulldrv/null_driver_gen.cpp.tmpl b/vulkan/nulldrv/null_driver_gen.cpp.tmpl
index 03a3d96..9b48869 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp.tmpl
+++ b/vulkan/nulldrv/null_driver_gen.cpp.tmpl
@@ -1,3 +1,19 @@
+{{/*
+ * 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 "../api/templates/vulkan_common.tmpl"}}
{{Global "clang-format" (Strings "clang-format" "-style=file")}}
{{Macro "DefineGlobals" $}}
diff --git a/vulkan/patches/README b/vulkan/patches/README
new file mode 100644
index 0000000..64ccf5d
--- /dev/null
+++ b/vulkan/patches/README
@@ -0,0 +1,19 @@
+frameworks/native/vulkan/patches
+================================
+Each subdirectory corresponds to a sequence of patches. These are
+"virtual branches": we only have one shared branch, so these let us
+share experimental or auxiliary changes without disturbing the main
+branch.
+
+To apply:
+$ cd <somewhere in target git repo>
+$ git am $VULKAN_PATCHES/$PATCH_DIR/*
+
+
+frameworks_base-apk_library_dir
+-------------------------------
+This branch is for frameworks/base. It modifies the framework to
+inform the Vulkan loader, during activity startup, where the
+activity's native library directory. The loader will search this
+directory for layer libraries. Without this change, layers will only
+be loaded from a global location under /data.
diff --git a/vulkan/patches/frameworks_base-apk_library_dir/0001-Adding-plumbing-for-passing-the-lib-directory.patch b/vulkan/patches/frameworks_base-apk_library_dir/0001-Adding-plumbing-for-passing-the-lib-directory.patch
new file mode 100644
index 0000000..81022d6
--- /dev/null
+++ b/vulkan/patches/frameworks_base-apk_library_dir/0001-Adding-plumbing-for-passing-the-lib-directory.patch
@@ -0,0 +1,133 @@
+From 5c7e465f1d11bccecdc5cacce87d1fd7deeb5adb Mon Sep 17 00:00:00 2001
+From: Michael Lentine <mlentine@google.com>
+Date: Mon, 14 Sep 2015 13:28:25 -0500
+Subject: [PATCH] Adding plumbing for passing the lib directory.
+
+Added call in handleBindApplication which will pass the library path into
+HardwareRender which then passes it to libvulkan through ThreadedRenderer's
+jni interface.
+
+Change-Id: Ie5709ac46f47c4af5c020d604a479e78745d7777
+---
+ core/java/android/app/ActivityThread.java | 7 +++++--
+ core/java/android/view/HardwareRenderer.java | 11 +++++++++++
+ core/java/android/view/ThreadedRenderer.java | 1 +
+ core/jni/Android.mk | 2 ++
+ core/jni/android_view_ThreadedRenderer.cpp | 15 +++++++++++++++
+ 5 files changed, 34 insertions(+), 2 deletions(-)
+
+diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
+index da21eaf..76608c6 100644
+--- a/core/java/android/app/ActivityThread.java
++++ b/core/java/android/app/ActivityThread.java
+@@ -4520,8 +4520,11 @@ public final class ActivityThread {
+ } else {
+ Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
+ }
+- }
+-
++ }
++
++ // Add the lib dir path to hardware renderer so that vulkan layers
++ // can be searched for within that directory.
++ HardwareRenderer.setLibDir(data.info.getLibDir());
+
+ final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
+ DateFormat.set24HourTimePref(is24Hr);
+diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
+index 5e58250..ed99115 100644
+--- a/core/java/android/view/HardwareRenderer.java
++++ b/core/java/android/view/HardwareRenderer.java
+@@ -301,6 +301,17 @@ public abstract class HardwareRenderer {
+ }
+
+ /**
++ * Sets the library directory to use as a search path for vulkan layers.
++ *
++ * @param libDir A directory that contains vulkan layers
++ *
++ * @hide
++ */
++ public static void setLibDir(String libDir) {
++ ThreadedRenderer.setupVulkanLayerPath(libDir);
++ }
++
++ /**
+ * Indicates that the specified hardware layer needs to be updated
+ * as soon as possible.
+ *
+diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
+index f6119e2..d3e5175 100644
+--- a/core/java/android/view/ThreadedRenderer.java
++++ b/core/java/android/view/ThreadedRenderer.java
+@@ -492,6 +492,7 @@ public class ThreadedRenderer extends HardwareRenderer {
+ }
+
+ static native void setupShadersDiskCache(String cacheFile);
++ static native void setupVulkanLayerPath(String layerPath);
+
+ private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
+ private static native void nSetProcessStatsBuffer(long nativeProxy, int fd);
+diff --git a/core/jni/Android.mk b/core/jni/Android.mk
+index 6b07a47..438e95b 100644
+--- a/core/jni/Android.mk
++++ b/core/jni/Android.mk
+@@ -177,6 +177,7 @@ LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/android/graphics \
+ $(LOCAL_PATH)/../../libs/hwui \
+ $(LOCAL_PATH)/../../../native/opengl/libs \
++ $(LOCAL_PATH)/../../../native/vulkan/include \
+ $(call include-path-for, bluedroid) \
+ $(call include-path-for, libhardware)/hardware \
+ $(call include-path-for, libhardware_legacy)/hardware_legacy \
+@@ -225,6 +226,7 @@ LOCAL_SHARED_LIBRARIES := \
+ libEGL \
+ libGLESv1_CM \
+ libGLESv2 \
++ libvulkan \
+ libETC1 \
+ libhardware \
+ libhardware_legacy \
+diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
+index 47132f4..69e8ca6 100644
+--- a/core/jni/android_view_ThreadedRenderer.cpp
++++ b/core/jni/android_view_ThreadedRenderer.cpp
+@@ -27,6 +27,7 @@
+ #include <EGL/egl.h>
+ #include <EGL/eglext.h>
+ #include <EGL/egl_cache.h>
++#include <vulkan/vulkan_loader_data.h>
+
+ #include <utils/StrongPointer.h>
+ #include <android_runtime/android_view_Surface.h>
+@@ -448,6 +449,18 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job
+ }
+
+ // ----------------------------------------------------------------------------
++// Layers
++// ----------------------------------------------------------------------------
++
++static void android_view_ThreadedRenderer_setupVulkanLayerPath(JNIEnv* env, jobject clazz,
++ jstring layerPath) {
++
++ const char* layerArray = env->GetStringUTFChars(layerPath, NULL);
++ vulkan::LoaderData::GetInstance().layer_path = layerArray;
++ env->ReleaseStringUTFChars(layerPath, layerArray);
++}
++
++// ----------------------------------------------------------------------------
+ // JNI Glue
+ // ----------------------------------------------------------------------------
+
+@@ -487,6 +500,8 @@ static JNINativeMethod gMethods[] = {
+ { "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData },
+ { "setupShadersDiskCache", "(Ljava/lang/String;)V",
+ (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
++ { "setupVulkanLayerPath", "(Ljava/lang/String;)V",
++ (void*) android_view_ThreadedRenderer_setupVulkanLayerPath },
+ };
+
+ int register_android_view_ThreadedRenderer(JNIEnv* env) {
+--
+2.6.0.rc2.230.g3dd15c0
+
diff --git a/vulkan/tools/Android.mk b/vulkan/tools/Android.mk
index 98ffa0f..9ea5f14 100644
--- a/vulkan/tools/Android.mk
+++ b/vulkan/tools/Android.mk
@@ -1,3 +1,17 @@
+# 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.
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
index 019032a..e1eb129 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -1,3 +1,19 @@
+/*
+ * 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 <inttypes.h>
#include <sstream>
#include <stdlib.h>