1 // asciidoc -b html5 -d book -f implementors_guide.conf implementors_guide.adoc 2 = Vulkan on Android Implementor's Guide = 3 :toc: right 4 :numbered: 5 :revnumber: 5 6 7 This document is intended for GPU IHVs writing Vulkan drivers for Android, and OEMs integrating them for specific devices. It describes how a Vulkan driver interacts with the system, how GPU-specific tools should be installed, and Android-specific requirements. 8 9 == Architecture == 10 11 The primary interface between Vulkan applications and a device's Vulkan driver is the loader, which is part of AOSP and installed at +/system/lib[64]/libvulkan.so+. The loader provides the core Vulkan API entry points, as well as entry points of a few extensions that are required on Android and always present. In particular, the window system integration (WSI) extensions are exported by the loader and primarily implemented in it rather than the driver. The loader also supports enumerating and loading layers which can expose additional extensions and/or intercept core API calls on their way to the driver. 12 13 The NDK will include a stub +libvulkan.so+ exporting the same symbols as the loader. Calling the Vulkan functions exported from +libvulkan.so+ will enter trampoline functions in the loader which will dispatch to the appropriate layer or driver based on their first argument. The +vkGet*ProcAddr+ calls will return the function pointers that the trampolines would dispatch to, so calling through these function pointers rather than the exported symbols will be slightly more efficient since it skips the trampoline and dispatch. 14 15 === Driver Enumeration and Loading === 16 17 Android expects the GPUs available to the system to be known when the system image is built, so its driver enumeration process isn't as elaborate as on other platforms. The loader will use the existing HAL mechanism for discovering and loading the driver. As of this writing, the preferred paths for 32-bit and 64-bit Vulkan drivers are: 18 19 /vendor/lib/hw/vulkan.<ro.product.platform>.so 20 /vendor/lib64/hw/vulkan.<ro.product.platform>.so 21 22 where +<ro.product.platform>+ is replaced by the value of the system property of that name. See https://android.googlesource.com/platform/hardware/libhardware/+/master/hardware.c[libhardware/hardware.c] for details and supported alternative locations. 23 24 The Vulkan +hw_module_t+ derivative is currently trivial. If support for multiple drivers is ever added, the HAL module will export a list of strings that can be passed to the module +open+ call. For the time being, only one driver is supported, and the constant string +HWVULKAN_DEVICE_0+ is passed to +open+. 25 26 The Vulkan +hw_device_t+ derivative corresponds to a single driver, though that driver can support multiple Vulkan physical devices. The +hw_device_t+ structure contains a function pointer for the +vkGetInstanceProcAddr+ function. The loader finds all other driver Vulkan functions by calling that +vkGetInstanceProcAddr+ function. 27 28 === Layer Discovery and Loading === 29 30 Android's security model and policies differ significantly from other platforms. In particular, Android does not allow loading external code into a non-debuggable process on production (non-rooted) devices, nor does it allow external code to inspect or control the process's memory/state/etc. This includes a prohibition on saving core dumps, API traces, etc. to disk for later inspection. So only layers delivered as part of the application will be enabled on production devices, and drivers must also not provide functionality that violates these policies. 31 32 There are three major use cases for layers: 33 34 1. Development-time layers: validation layers, shims for tracing/profiling/debugging tools, etc. These shouldn't be installed on the system image of production devices: they would be a waste of space for most users, and they should be updateable without requiring a system update. A developer wishing to use one of these during development has the ability to modify their application package (e.g. adding a file to their native libraries directory). IHV and OEM engineers who are trying to diagnose failures in shipping, unmodifiable apps are assumed to have access to non-production (rooted) builds of the system image. 35 36 2. Utility layers, such as a layer that implements a heap for device memory. These layers will almost always expose extensions. Developers choose which layers, and which versions of those layers, to use in their application; different applications that use the same layer may still use different versions. Developers will choose which of these layers to ship in their application package. 37 38 3. Injected layers, like framerate, social network, or game launcher overlays, which are provided by the user or some other application without the application's knowledge or consent. These violate Android's security policies and will not be supported. 39 40 In the normal state the loader will only search in the application's normal library search path (as defined by the system ClassLoader) for layers. It will attempt to load any shared library named +libVkLayer_*.so+ as a layer library. Android does not use manifests to describe layers: because layers must have been deliberately included in the application by the developer, the motivation for manifests on other platforms don't apply. 41 42 On debuggable devices (+ro.debuggable+ property exists and is non-zero, generally rooted or engineering builds) the loader will also search the directory +/data/local/debug/vulkan+ and attempt to load layer libraries it finds there. This directory doesn't exist by default. On Android N and later, because this location is writable by adb, SELinux policies prevent mapping code located here as executable. So to use layers from here, SELinux enforcement must be disabled: +adb shell setenforce 0+. This mechanism is not intended for application developers, only for IHV and OEM engineers working on test devices that don't have private or sensitive data. 43 44 Our goal is to allow layers to be ported with only build-environment changes between Android and other platforms. For this to work, layers must properly implement things like +vkGetInstanceLayerProperties+ and +vkGetInstanceExtensionProperties+, even though the LunarG loader doesn't use them (it gets the information from manifests instead). 45 46 == Window System Integration == 47 48 The +vk_wsi_swapchin+ and +vk_wsi_device_swapchain+ extensions are primarily be implemented by the platform and live in +libvulkan.so+. The +VkSwapchain+ object and all interaction with +ANativeWindow+ will be handled by the platform and not exposed to drivers. The WSI implementation will rely on a few private interfaces to the driver for this implementation. These will be loaded through the driver's +vkGetDeviceProcAddr+ functions, after passing through any enabled layers. 49 50 Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags that depend not only on +format+ and +imageUsage+, but also on the intended usage of the swapchain. The swapchain usage bits are defined as 51 [source,c] 52 ---- 53 typedef enum VkSwapchainImageUsageFlagBitsANDROID { 54 VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID = 0x00000001, 55 VK_SWAPCHAIN_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF 56 } VkSwapchainImageUsageFlagBitsANDROID; 57 typedef VkFlags VkSwapchainImageUsageFlagsANDROID; 58 ---- 59 60 Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags. When creating a swapchain, the platform will ask the driver to translate the requested format and image usage flags into gralloc usage flags by calling 61 [source,c] 62 ---- 63 VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage2ANDROID( 64 VkDevice device, 65 VkFormat format, 66 VkImageUsageFlags imageUsage, 67 VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, 68 uint64_t* grallocConsumerUsage, 69 uint64_t* grallocProducerUsage, 70 ); 71 ---- 72 The +format+ and +imageUsage+ parameters are taken from the +VkSwapchainCreateInfoKHR+ structure. The driver should fill +*grallocConsumerUsage+ and +*grallocProducerUsage+ with the gralloc usage flags it requires for that format and usage. These will be combined with the usage flags requested by the swapchain consumer when allocating buffers. 73 74 An older version of this function is deprecated but still supported for backwards compatibility; it will be used if +vkGetSwapchainGrallocUsage2ANDROID+ is not supported: 75 [source,c] 76 ---- 77 VkResult VKAPI vkGetSwapchainGrallocUsageANDROID( 78 VkDevice device, 79 VkFormat format, 80 VkImageUsageFlags imageUsage, 81 int* grallocUsage 82 ); 83 ---- 84 85 +VkNativeBufferANDROID+ is a +vkCreateImage+ extension structure for creating an image backed by a gralloc buffer. This structure is provided to +vkCreateImage+ in the +VkImageCreateInfo+ structure chain. Calls to +vkCreateImage+ with this structure will happen during the first call to +vkGetSwapChainInfoWSI(.. VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI ..)+. The WSI implementation will allocate the number of native buffers requested for the swapchain, then create a +VkImage+ for each one. 86 87 [source,c] 88 ---- 89 typedef struct { 90 VkStructureType sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID 91 const void* pNext; 92 93 // Buffer handle and stride returned from gralloc alloc() 94 buffer_handle_t handle; 95 int stride; 96 97 // Gralloc format and usage requested when the buffer was allocated. 98 int format; 99 int usage; // deprecated 100 struct { 101 uint64_t consumer; 102 uint64_t producer; 103 } usage2; 104 } VkNativeBufferANDROID; 105 ---- 106 107 When creating a gralloc-backed image, the +VkImageCreateInfo+ will have: 108 [source,txt] 109 ---- 110 .imageType = VK_IMAGE_TYPE_2D 111 .format = a VkFormat matching the format requested for the gralloc buffer 112 .extent = the 2D dimensions requested for the gralloc buffer 113 .mipLevels = 1 114 .arraySize = 1 115 .samples = 1 116 .tiling = VK_IMAGE_TILING_OPTIMAL 117 .usage = VkSwapChainCreateInfoWSI::imageUsageFlags 118 .flags = 0 119 .sharingMode = VkSwapChainCreateInfoWSI::sharingMode 120 .queueFamilyCount = VkSwapChainCreateInfoWSI::queueFamilyCount 121 .pQueueFamilyIndices = VkSwapChainCreateInfoWSI::pQueueFamilyIndices 122 ---- 123 124 Additionally, when any swapchain image usage flags are required for the swapchain, the platform will provide a +VkSwapchainImageCreateInfoANDROID+ extension structure in the +VkImageCreateInfo+ chain provided to +vkCreateImage+, containing the swapchain image usage flags: 125 [source,c] 126 ---- 127 typedef struct { 128 VkStructureType sType; // must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID 129 const void* pNext; 130 131 VkSwapchainImageUsageFlagsANDROID usage; 132 } VkSwapchainImageCreateInfoANDROID; 133 ---- 134 135 +vkAcquireImageANDROID+ acquires ownership of a swapchain image and imports an 136 externally-signalled native fence into both an existing VkSemaphore object 137 and an existing VkFence object: 138 139 [source,c] 140 ---- 141 VkResult VKAPI vkAcquireImageANDROID( 142 VkDevice device, 143 VkImage image, 144 int nativeFenceFd, 145 VkSemaphore semaphore, 146 VkFence fence 147 ); 148 ---- 149 150 This function is called during +vkAcquireNextImageWSI+ to import a native 151 fence into the +VkSemaphore+ and +VkFence+ objects provided by the 152 application. Both semaphore and fence objects are optional in this call. The 153 driver may also use this opportunity to recognize and handle any external 154 changes to the gralloc buffer state; many drivers won't need to do anything 155 here. This call puts the +VkSemaphore+ and +VkFence+ into the same "pending" 156 state as +vkQueueSignalSemaphore+ and +vkQueueSubmit+ respectively, so queues 157 can wait on the semaphore and the application can wait on the fence. Both 158 objects become signalled when the underlying native fence signals; if the 159 native fence has already signalled, then the semaphore will be in the signalled 160 state when this function returns. The driver takes ownership of the fence fd 161 and is responsible for closing it when no longer needed. It must do so even if 162 neither a semaphore or fence object is provided, or even if 163 +vkAcquireImageANDROID+ fails and returns an error. If +fenceFd+ is -1, it 164 is as if the native fence was already signalled. 165 166 +vkQueueSignalReleaseImageANDROID+ prepares a swapchain image for external use, and creates a native fence and schedules it to be signalled when prior work on the queue has completed. 167 168 [source,c] 169 ---- 170 VkResult VKAPI vkQueueSignalReleaseImageANDROID( 171 VkQueue queue, 172 uint32_t waitSemaphoreCount, 173 const VkSemaphore* pWaitSemaphores, 174 VkImage image, 175 int* pNativeFenceFd 176 ); 177 ---- 178 179 This will be called during +vkQueuePresentWSI+ on the provided queue. Effects are similar to +vkQueueSignalSemaphore+, except with a native fence instead of a semaphore. The native fence must: not signal until the +waitSemaphoreCount+ semaphores in +pWaitSemaphores+ have signaled. Unlike +vkQueueSignalSemaphore+, however, this call creates and returns the synchronization object that will be signalled rather than having it provided as input. If the queue is already idle when this function is called, it is allowed but not required to set +*pNativeFenceFd+ to -1. The file descriptor returned in +*pNativeFenceFd+ is owned and will be closed by the caller. Many drivers will be able to ignore the +image+ parameter, but some may need to prepare CPU-side data structures associated with a gralloc buffer for use by external image consumers. Preparing buffer contents for use by external consumers should have been done asynchronously as part of transitioning the image to +VK_IMAGE_LAYOUT_PRESENT_SRC_KHR+. 180 181 If +image+ was created with +VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID+, then the driver must tolerate +vkQueueSignalReleaseImageANDROID+ being called repeatedly without intervening calls to +vkAcquireImageANDROID+. 182 183 == History == 184 185 . *2015-07-08* Initial version 186 . *2015-08-16* 187 * Renamed to Implementor's Guide 188 * Wording and formatting changes 189 * Updated based on resolution of Khronos bug 14265 190 * Deferred support for multiple drivers 191 . *2015-11-04* 192 * Added vkGetSwapchainGrallocUsageANDROID 193 * Replaced vkImportNativeFenceANDROID and vkQueueSignalNativeFenceANDROID 194 with vkAcquireImageANDROID and vkQueueSignalReleaseImageANDROID, to allow 195 drivers to known the ownership state of swapchain images. 196 . *2015-12-03* 197 * Added a VkFence parameter to vkAcquireImageANDROID corresponding to the 198 parameter added to vkAcquireNextImageKHR. 199 . *2016-01-08* 200 * Added waitSemaphoreCount and pWaitSemaphores parameters to vkQueueSignalReleaseImageANDROID. 201 . *2016-06-17* 202 * Updates to reflect final behavior, closed some TBDs now that they've BDed. 203 . *2017-01-06* 204 * Extension version 6 205 * Added VkSwapchainImageUsageFlagBitsANDROID 206 * Added vkGetSwapchainGrallocUsage2ANDROID 207 * Added VkSwapchainImageCreateInfoANDROID 208 . *2017-02-09* 209 * Extended vkGetSwapchainGrallocUsage2ANDROID and VkNativeBufferANDROID to use gralloc1-style usage bitfields.