OSDN Git Service

vulkan: add initial vkandroid doc
authorJesse Hall <jessehall@google.com>
Sun, 16 Aug 2015 00:56:53 +0000 (17:56 -0700)
committerJesse Hall <jessehall@google.com>
Mon, 25 Jan 2016 21:49:31 +0000 (13:49 -0800)
Change-Id: I40aa41941bfbe0f33f30446e83ef62f5358e47d4
(cherry picked from commit 64b41615ead7f7ba1df309889cbbc7aee60cb3f4)

vulkan/doc/vkandroid-docinfo.html [new file with mode: 0644]
vulkan/doc/vkandroid.adoc [new file with mode: 0644]
vulkan/doc/vkandroid.conf [new file with mode: 0644]
vulkan/doc/vkandroid.html [new file with mode: 0644]

diff --git a/vulkan/doc/vkandroid-docinfo.html b/vulkan/doc/vkandroid-docinfo.html
new file mode 100644 (file)
index 0000000..69b8c61
--- /dev/null
@@ -0,0 +1,23 @@
+<style type="text/css">
+
+code,div.listingblock {
+       max-width: 68em;
+}
+
+p {
+    max-width: 50em;
+}
+
+table {
+    max-width: 50em;
+}
+
+table.tableblock {
+  border-width: 1px;
+}
+
+h2 {
+    max-width: 35em;
+}
+
+</style>
diff --git a/vulkan/doc/vkandroid.adoc b/vulkan/doc/vkandroid.adoc
new file mode 100644 (file)
index 0000000..f1e7032
--- /dev/null
@@ -0,0 +1,157 @@
+// asciidoc -b html5 -d book -f vkandroid.conf vkandroid.adoc
+= Vulkan Android Platform Integration =
+:toc: right
+:numbered:
+:revnumber: 1
+
+This document describes how the Vulkan API is integrated into Android. It focuses on the interfaces and division of responsibilities between applications, the platform, and drivers rather than internal implementation details of each of them.
+
+This is still a fairly rough draft; details will be filled in over time.
+
+== Loader ==
+
+The Android Vulkan loader will be implemented in +/system/lib[64]/libvulkan.so+. It will export all of the Vulkan function symbols, as well as any extension functions that are mandatory on Android (in particular the window-system integration functions). Non-mandatory extension functions must be queried dynamically using +vkGet*ProcAddr+.
+
+The NDK will include a stub +libvulkan.so+ exporting the same symbols. 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 in general (with a few exceptions that need special loader support) 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.
+
+=== Driver Enumeration and Loading ===
+
+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 other platforms. The loader will use the existing HAL mechanism (see https://android.googlesource.com/platform/hardware/libhardware/+/lollipop-mr1-release/include/hardware/hardware.h[hardware.h]) for discovering and loading the driver. As of this writing, the preferred paths for 32-bit and 64-bit Vulkan drivers are:
+
+    /vendor/lib/hw/vulkan.<ro.product.platform>.so
+    /vendor/lib64/hw/vulkan.<ro.product.platform>.so
+
+where +<ro.product.platform>+ is replaced by the value of the system property of that name. See https://android.googlesource.com/platform/hardware/libhardware/+/lollipop-mr1-release/hardware.c[libhardware/hardware.c] for details and supported alternative locations.
+
+The Vulkan +hw_module_t+ derivative will have fields that provide a list of available device names. These names are strings, but the contents are arbitrary; they will only be passed to the module +open+ call. The ability to expose more than one device is reserved for future use; existing Android products will only have one device, and the first implementation of the loader may ignore all devices except the first.
+
+The Vulkan +hw_device_t+ derivative corresponds to a single ICD. The structure will be extended to export +vkGetGlobalExtensionProperties+, +vkCreateInstance+, and +vkGetInstanceProcAddr+ functions. The loader will find all other VkInstance and VkPhysicalDevice functions by calling +vkGetInstanceProcAddr+.
+
+=== Layer Discovery and Loading ===
+
+Details are still being worked out. The Android app distribution model as well as security requirements differ from other platforms enough that layer discovery and loading will work somewhat differently.
+
+In particular, Android security policy does not allow loading external code into a non-debuggable process on production devices, or allowing 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 in these situations, and drivers must also not provide functionality that violates these policies.
+
+There are three major use cases for layers:
+
+1. Development-time layers: validation layers, shims for tracing/profiling/debugging tools, etc. These don't need to be on end-user devices, and application developers have the ability to modify their application package (e.g. adding a file to their native libraries directory) to use them.
++
+An important special case of this is IHV and OEM engineers who are trying to diagnose failures in shipping, unmodifiable apps. However, these engineers typically have access to non-production builds of the system image.
+
+2. Utility layers, such as a layer that implements a device memory heap. These layers will almost always expose extensions. Developers choose which layers, and which versions of those layers, to use in their application.
+
+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.
+
+In the normal state the loader will only search in the application's native library directory for layers; it will probably just try to load any library with a name matching a particular pattern(e.g. +libvklayer_foo.so+). It will probably not need a separate manifest file; the developer deliberately included these layers, so the reasons to avoid loading libraries before enabling them don't apply.
+
+On debuggable devices (+ro.debuggable+ property exists and is non-zero, generally rooted or engineering builds) or debuggable processes (prctl(PR_GET_DUMPABLE)==1, based on the application's manifest), the loader may also search an adb-writeable location on /data for layers. It's not clear whether this is useful; in all the cases it could be used, the layer could be just as easily put in the application's native library directory.
+
+Finally, the loader may include a built-in validation layer that it will enable based on settings in the Developer Options menu, which would send validation errors or warnings to the system log. Drivers may be able to emit additional hardware-specific errors/warnings through this mechanism. This layer would not be enumerated through the API. This is intended to allow cooperative end-users to collect extra information about failures from unmodified applications on unmodified devices to aid triage/diagnosis of difficult-to-reproduce problems. The functionality is intentionally limited to minimize security and privacy risk.
+
+== Window System Integration ==
+
+TODO: Add more internal implementation details.
+
+The vk_wsi_swapchin and vk_wsi_device_swapchain extensions will 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:
+
+[source,c]
+----
+// 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.
+//
+// TBD: During swapchain re-creation (using 'oldSwapChain'), we may have to
+// defer allocation of new gralloc buffers until old buffers have been released.
+// If so, the vkCreateImage calls will be deferred until the first
+// vkAcquireNextImageWSI() that would return the new image.
+//
+// When creating a gralloc-backed image, the VkImageCreateInfo will have:
+//   .imageType     = VK_IMAGE_TYPE_2D
+//   .format        = a VkFormat matching the format requested for the gralloc buffer
+//   .extent        = the 2D dimensions requested for the gralloc buffer
+//   .mipLevels     = 1
+//   .arraySize     = 1
+//   .samples       = 1
+//   .tiling        = VK_IMAGE_TILING_OPTIMAL
+//   .usage         = VkSwapChainCreateInfoWSI::imageUsageFlags
+//   .flags         = 0
+//   .sharingMode   = TBD (see below)
+//   .queueFamilyCount = TBD (see below)
+//   .pQueueFamilyIndices = TBD (see below)
+
+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;
+----
+
+It's not clear how we should set the +sharingMode+, +queueFamilyCount+, and +pQueueFamilyIndices+ fields. See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=14265[bug 14265] for details.
+
+[source,c]
+----
+// vkImportNativeFenceANDROID imports an externally-signalled native fence into
+// an existing VkSemaphore object.
+//
+// This function is called during vkAcquireNextImageWSI to import a native fence
+// into the VkSemaphore object provided by the application. This call puts the
+// VkSemaphore into the same "pending" state as vkQueueSignalSemaphore, so
+// queues can wait on the semaphore. The VkSemaphore signals when the underlying
+// native fence signals; if the fence has already signalled, then the semaphore
+// will be in the signalled state when this function returns.
+//
+// The driver takes ownership of the fence fd and is responsible for closing it
+// when the VkSemaphore is destroyed, when a different native fence is imported,
+// or any other condition that replaces the VkSemaphore's underlying
+// synchronization object.
+//
+// If fenceFd is -1, the VkSemaphore will be considered signalled immediately,
+// but it can still be passed to vkQueueWaitSemaphore.
+
+VkResult VKAPI vkImportNativeFenceANDROID(
+    VkDevice        device,
+    VkSemaphore     semaphore,
+    int             nativeFenceFd
+);
+----
+
+[source,c]
+----
+// vkQueueSignalNativeFenceANDROID creates a native fence and schedules it to be
+// signalled when prior work on the queue has completed.
+//
+// This will be called during vkQueuePresentWSI on the provided queue.
+//
+// Effects are similar to vkQueueSignalSemaphore, except with a native fence
+// instead of a semaphore. 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.
+
+VkResult VKAPI vkQueueSignalNativeFenceANDROID(
+    VkQueue         queue,
+    int*            pNativeFenceFd);
+----
+
+== History ==
+
+1. *2015-07-08* Initial version
diff --git a/vulkan/doc/vkandroid.conf b/vulkan/doc/vkandroid.conf
new file mode 100644 (file)
index 0000000..572a4d9
--- /dev/null
@@ -0,0 +1,5 @@
+[attributes]
+newline=\n
+
+[replacements]
+\+\/-=&plusmn;
diff --git a/vulkan/doc/vkandroid.html b/vulkan/doc/vkandroid.html
new file mode 100644 (file)
index 0000000..e36348b
--- /dev/null
@@ -0,0 +1,922 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="generator" content="AsciiDoc 8.6.9">
+<title>Vulkan Android Platform Integration</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+  font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+  font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+  margin: 1em 5% 1em 5%;
+}
+
+a {
+  color: blue;
+  text-decoration: underline;
+}
+a:visited {
+  color: fuchsia;
+}
+
+em {
+  font-style: italic;
+  color: navy;
+}
+
+strong {
+  font-weight: bold;
+  color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  color: #527bbd;
+  margin-top: 1.2em;
+  margin-bottom: 0.5em;
+  line-height: 1.3;
+}
+
+h1, h2, h3 {
+  border-bottom: 2px solid silver;
+}
+h2 {
+  padding-top: 0.5em;
+}
+h3 {
+  float: left;
+}
+h3 + * {
+  clear: left;
+}
+h5 {
+  font-size: 1.0em;
+}
+
+div.sectionbody {
+  margin-left: 0;
+}
+
+hr {
+  border: 1px solid silver;
+}
+
+p {
+  margin-top: 0.5em;
+  margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+  margin-top: 0;
+}
+ul > li     { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+  font-family: "Courier New", Courier, monospace;
+  font-size: inherit;
+  color: navy;
+  padding: 0;
+  margin: 0;
+}
+pre {
+  white-space: pre-wrap;
+}
+
+#author {
+  color: #527bbd;
+  font-weight: bold;
+  font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+  font-size: small;
+  border-top: 2px solid silver;
+  padding-top: 0.5em;
+  margin-top: 4.0em;
+}
+#footer-text {
+  float: left;
+  padding-bottom: 0.5em;
+}
+#footer-badges {
+  float: right;
+  padding-bottom: 0.5em;
+}
+
+#preamble {
+  margin-top: 1.5em;
+  margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+div.admonitionblock {
+  margin-top: 2.0em;
+  margin-bottom: 2.0em;
+  margin-right: 10%;
+  color: #606060;
+}
+
+div.content { /* Block element content. */
+  padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+  color: #527bbd;
+  font-weight: bold;
+  text-align: left;
+  margin-top: 1.0em;
+  margin-bottom: 0.5em;
+}
+div.title + * {
+  margin-top: 0;
+}
+
+td div.title:first-child {
+  margin-top: 0.0em;
+}
+div.content div.title:first-child {
+  margin-top: 0.0em;
+}
+div.content + div.title {
+  margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+  background: #ffffee;
+  border: 1px solid #dddddd;
+  border-left: 4px solid #f0f0f0;
+  padding: 0.5em;
+}
+
+div.listingblock > div.content {
+  border: 1px solid #dddddd;
+  border-left: 5px solid #f0f0f0;
+  background: #f8f8f8;
+  padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+  padding-left: 1.0em;
+  margin-left: 1.0em;
+  margin-right: 10%;
+  border-left: 5px solid #f0f0f0;
+  color: #888;
+}
+
+div.quoteblock > div.attribution {
+  padding-top: 0.5em;
+  text-align: right;
+}
+
+div.verseblock > pre.content {
+  font-family: inherit;
+  font-size: inherit;
+}
+div.verseblock > div.attribution {
+  padding-top: 0.75em;
+  text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+  text-align: left;
+}
+
+div.admonitionblock .icon {
+  vertical-align: top;
+  font-size: 1.1em;
+  font-weight: bold;
+  text-decoration: underline;
+  color: #527bbd;
+  padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+  padding-left: 0.5em;
+  border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+  border-left: 3px solid #dddddd;
+  padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+  margin-top: 0.8em;
+  margin-bottom: 0.8em;
+}
+dt {
+  margin-top: 0.5em;
+  margin-bottom: 0;
+  font-style: normal;
+  color: navy;
+}
+dd > *:first-child {
+  margin-top: 0.1em;
+}
+
+ul, ol {
+    list-style-position: outside;
+}
+ol.arabic {
+  list-style-type: decimal;
+}
+ol.loweralpha {
+  list-style-type: lower-alpha;
+}
+ol.upperalpha {
+  list-style-type: upper-alpha;
+}
+ol.lowerroman {
+  list-style-type: lower-roman;
+}
+ol.upperroman {
+  list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+  margin-top: 0.1em;
+  margin-bottom: 0.1em;
+}
+
+tfoot {
+  font-weight: bold;
+}
+td > div.verse {
+  white-space: pre;
+}
+
+div.hdlist {
+  margin-top: 0.8em;
+  margin-bottom: 0.8em;
+}
+div.hdlist tr {
+  padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+  font-weight: bold;
+}
+td.hdlist1 {
+  vertical-align: top;
+  font-style: normal;
+  padding-right: 0.8em;
+  color: navy;
+}
+td.hdlist2 {
+  vertical-align: top;
+}
+div.hdlist.compact tr {
+  margin: 0;
+  padding-bottom: 0;
+}
+
+.comment {
+  background: yellow;
+}
+
+.footnote, .footnoteref {
+  font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+  vertical-align: super;
+}
+
+#footnotes {
+  margin: 20px 0 20px 0;
+  padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+  margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+  border: none;
+  border-top: 1px solid silver;
+  height: 1px;
+  text-align: left;
+  margin-left: 0;
+  width: 20%;
+  min-width: 100px;
+}
+
+div.colist td {
+  padding-right: 0.5em;
+  padding-bottom: 0.3em;
+  vertical-align: top;
+}
+div.colist td img {
+  margin-top: 0.3em;
+}
+
+@media print {
+  #footer-badges { display: none; }
+}
+
+#toc {
+  margin-bottom: 2.5em;
+}
+
+#toctitle {
+  color: #527bbd;
+  font-size: 1.1em;
+  font-weight: bold;
+  margin-top: 1.0em;
+  margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+div.toclevel2 {
+  margin-left: 2em;
+  font-size: 0.9em;
+}
+div.toclevel3 {
+  margin-left: 4em;
+  font-size: 0.9em;
+}
+div.toclevel4 {
+  margin-left: 6em;
+  font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+div.tableblock > table {
+  border: 3px solid #527bbd;
+}
+thead, p.table.header {
+  font-weight: bold;
+  color: #527bbd;
+}
+p.table {
+  margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+  border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+  border-left-style: none;
+  border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+  border-top-style: none;
+  border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+  font-weight: bold;
+  color: #527bbd;
+}
+p.tableblock {
+  margin-top: 0;
+}
+table.tableblock {
+  border-width: 3px;
+  border-spacing: 0px;
+  border-style: solid;
+  border-color: #527bbd;
+  border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+  border-width: 1px;
+  padding: 4px;
+  border-style: solid;
+  border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+  border-left-style: hidden;
+  border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+  border-top-style: hidden;
+  border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+  border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+  text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+  text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+  text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+  vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+  vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+  vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+  padding-top: 0.5em;
+  padding-bottom: 0.5em;
+  border-top: 2px solid silver;
+  border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+  border-style: none;
+}
+body.manpage div.sectionbody {
+  margin-left: 3em;
+}
+
+@media print {
+  body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = {  // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+  function getText(el) {
+    var text = "";
+    for (var i = el.firstChild; i != null; i = i.nextSibling) {
+      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+        text += i.data;
+      else if (i.firstChild != null)
+        text += getText(i);
+    }
+    return text;
+  }
+
+  function TocEntry(el, text, toclevel) {
+    this.element = el;
+    this.text = text;
+    this.toclevel = toclevel;
+  }
+
+  function tocEntries(el, toclevels) {
+    var result = new Array;
+    var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+    // Function that scans the DOM tree for header elements (the DOM2
+    // nodeIterator API would be a better technique but not supported by all
+    // browsers).
+    var iterate = function (el) {
+      for (var i = el.firstChild; i != null; i = i.nextSibling) {
+        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+          var mo = re.exec(i.tagName);
+          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+          }
+          iterate(i);
+        }
+      }
+    }
+    iterate(el);
+    return result;
+  }
+
+  var toc = document.getElementById("toc");
+  if (!toc) {
+    return;
+  }
+
+  // Delete existing TOC entries in case we're reloading the TOC.
+  var tocEntriesToRemove = [];
+  var i;
+  for (i = 0; i < toc.childNodes.length; i++) {
+    var entry = toc.childNodes[i];
+    if (entry.nodeName.toLowerCase() == 'div'
+     && entry.getAttribute("class")
+     && entry.getAttribute("class").match(/^toclevel/))
+      tocEntriesToRemove.push(entry);
+  }
+  for (i = 0; i < tocEntriesToRemove.length; i++) {
+    toc.removeChild(tocEntriesToRemove[i]);
+  }
+
+  // Rebuild TOC entries.
+  var entries = tocEntries(document.getElementById("content"), toclevels);
+  for (var i = 0; i < entries.length; ++i) {
+    var entry = entries[i];
+    if (entry.element.id == "")
+      entry.element.id = "_toc_" + i;
+    var a = document.createElement("a");
+    a.href = "#" + entry.element.id;
+    a.appendChild(document.createTextNode(entry.text));
+    var div = document.createElement("div");
+    div.appendChild(a);
+    div.className = "toclevel" + entry.toclevel;
+    toc.appendChild(div);
+  }
+  if (entries.length == 0)
+    toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+  // Delete existing footnote entries in case we're reloading the footnodes.
+  var i;
+  var noteholder = document.getElementById("footnotes");
+  if (!noteholder) {
+    return;
+  }
+  var entriesToRemove = [];
+  for (i = 0; i < noteholder.childNodes.length; i++) {
+    var entry = noteholder.childNodes[i];
+    if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+      entriesToRemove.push(entry);
+  }
+  for (i = 0; i < entriesToRemove.length; i++) {
+    noteholder.removeChild(entriesToRemove[i]);
+  }
+
+  // Rebuild footnote entries.
+  var cont = document.getElementById("content");
+  var spans = cont.getElementsByTagName("span");
+  var refs = {};
+  var n = 0;
+  for (i=0; i<spans.length; i++) {
+    if (spans[i].className == "footnote") {
+      n++;
+      var note = spans[i].getAttribute("data-note");
+      if (!note) {
+        // Use [\s\S] in place of . so multi-line matches work.
+        // Because JavaScript has no s (dotall) regex flag.
+        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+        spans[i].innerHTML =
+          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+          "' title='View footnote' class='footnote'>" + n + "</a>]";
+        spans[i].setAttribute("data-note", note);
+      }
+      noteholder.innerHTML +=
+        "<div class='footnote' id='_footnote_" + n + "'>" +
+        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+        n + "</a>. " + note + "</div>";
+      var id =spans[i].getAttribute("id");
+      if (id != null) refs["#"+id] = n;
+    }
+  }
+  if (n == 0)
+    noteholder.parentNode.removeChild(noteholder);
+  else {
+    // Process footnoterefs.
+    for (i=0; i<spans.length; i++) {
+      if (spans[i].className == "footnoteref") {
+        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+        href = href.match(/#.*/)[0];  // Because IE return full URL.
+        n = refs[href];
+        spans[i].innerHTML =
+          "[<a href='#_footnote_" + n +
+          "' title='View footnote' class='footnote'>" + n + "</a>]";
+      }
+    }
+  }
+},
+
+install: function(toclevels) {
+  var timerId;
+
+  function reinstall() {
+    asciidoc.footnotes();
+    if (toclevels) {
+      asciidoc.toc(toclevels);
+    }
+  }
+
+  function reinstallAndRemoveTimer() {
+    clearInterval(timerId);
+    reinstall();
+  }
+
+  timerId = setInterval(reinstall, 500);
+  if (document.addEventListener)
+    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+  else
+    window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install(2);
+/*]]>*/
+</script>
+</head>
+<body class="book">
+<div id="header">
+<h1>Vulkan Android Platform Integration</h1>
+<span id="revnumber">version 1</span>
+<div id="toc">
+  <div id="toctitle">Table of Contents</div>
+  <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
+</div>
+</div>
+<div id="content">
+<div id="preamble">
+<div class="sectionbody">
+<div class="paragraph"><p>This document describes how the Vulkan API is integrated into Android. It focuses on the interfaces and division of responsibilities between applications, the platform, and drivers rather than internal implementation details of each of them.</p></div>
+<div class="paragraph"><p>This is still a fairly rough draft; details will be filled in over time.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_loader">1. Loader</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Android Vulkan loader will be implemented in <span class="monospaced">/system/lib[64]/libvulkan.so</span>. It will export all of the Vulkan function symbols, as well as any extension functions that are mandatory on Android (in particular the window-system integration functions). Non-mandatory extension functions must be queried dynamically using <span class="monospaced">vkGet*ProcAddr</span>.</p></div>
+<div class="paragraph"><p>The NDK will include a stub <span class="monospaced">libvulkan.so</span> exporting the same symbols. Calling the Vulkan functions exported from <span class="monospaced">libvulkan.so</span> will enter trampoline functions in the loader which will dispatch to the appropriate layer or driver based on their first argument. The <span class="monospaced">vkGet*ProcAddr</span> calls will in general (with a few exceptions that need special loader support) 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.</p></div>
+<div class="sect2">
+<h3 id="_driver_enumeration_and_loading">1.1. Driver Enumeration and Loading</h3>
+<div class="paragraph"><p>Android expects the GPUs available to the system to be known when the system image is built, so its driver enumeration process isn&#8217;t as elaborate as other platforms. The loader will use the existing HAL mechanism (see <a href="https://android.googlesource.com/platform/hardware/libhardware/+/lollipop-mr1-release/include/hardware/hardware.h">hardware.h</a>) for discovering and loading the driver. As of this writing, the preferred paths for 32-bit and 64-bit Vulkan drivers are:</p></div>
+<div class="literalblock">
+<div class="content monospaced">
+<pre>/vendor/lib/hw/vulkan.&lt;ro.product.platform&gt;.so
+/vendor/lib64/hw/vulkan.&lt;ro.product.platform&gt;.so</pre>
+</div></div>
+<div class="paragraph"><p>where <span class="monospaced">&lt;ro.product.platform&gt;</span> is replaced by the value of the system property of that name. See <a href="https://android.googlesource.com/platform/hardware/libhardware/+/lollipop-mr1-release/hardware.c">libhardware/hardware.c</a> for details and supported alternative locations.</p></div>
+<div class="paragraph"><p>The Vulkan <span class="monospaced">hw_module_t</span> derivative will have fields that provide a list of available device names. These names are strings, but the contents are arbitrary; they will only be passed to the module <span class="monospaced">open</span> call. The ability to expose more than one device is reserved for future use; existing Android products will only have one device, and the first implementation of the loader may ignore all devices except the first.</p></div>
+<div class="paragraph"><p>The Vulkan <span class="monospaced">hw_device_t</span> derivative corresponds to a single ICD. The structure will be extended to export <span class="monospaced">vkGetGlobalExtensionProperties</span>, <span class="monospaced">vkCreateInstance</span>, and <span class="monospaced">vkGetInstanceProcAddr</span> functions. The loader will find all other VkInstance and VkPhysicalDevice functions by calling <span class="monospaced">vkGetInstanceProcAddr</span>.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_layer_discovery_and_loading">1.2. Layer Discovery and Loading</h3>
+<div class="paragraph"><p>Details are still being worked out. The Android app distribution model as well as security requirements differ from other platforms enough that layer discovery and loading will work somewhat differently.</p></div>
+<div class="paragraph"><p>In particular, Android security policy does not allow loading external code into a non-debuggable process on production devices, or allowing external code to inspect or control the process&#8217;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 in these situations, and drivers must also not provide functionality that violates these policies.</p></div>
+<div class="paragraph"><p>There are three major use cases for layers:</p></div>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+Development-time layers: validation layers, shims for tracing/profiling/debugging tools, etc. These don&#8217;t need to be on end-user devices, and application developers have the ability to modify their application package (e.g. adding a file to their native libraries directory) to use them.
+</p>
+<div class="paragraph"><p>An important special case of this is IHV and OEM engineers who are trying to diagnose failures in shipping, unmodifiable apps. However, these engineers typically have access to non-production builds of the system image.</p></div>
+</li>
+<li>
+<p>
+Utility layers, such as a layer that implements a device memory heap. These layers will almost always expose extensions. Developers choose which layers, and which versions of those layers, to use in their application.
+</p>
+</li>
+<li>
+<p>
+Injected layers, like framerate, social network, or game launcher overlays, which are provided by the user or some other application without the application&#8217;s knowledge or consent. These violate Android&#8217;s security policies and will not be supported.
+</p>
+</li>
+</ol></div>
+<div class="paragraph"><p>In the normal state the loader will only search in the application&#8217;s native library directory for layers; it will probably just try to load any library with a name matching a particular pattern(e.g. <span class="monospaced">libvklayer_foo.so</span>). It will probably not need a separate manifest file; the developer deliberately included these layers, so the reasons to avoid loading libraries before enabling them don&#8217;t apply.</p></div>
+<div class="paragraph"><p>On debuggable devices (<span class="monospaced">ro.debuggable</span> property exists and is non-zero, generally rooted or engineering builds) or debuggable processes (prctl(PR_GET_DUMPABLE)==1, based on the application&#8217;s manifest), the loader may also search an adb-writeable location on /data for layers. It&#8217;s not clear whether this is useful; in all the cases it could be used, the layer could be just as easily put in the application&#8217;s native library directory.</p></div>
+<div class="paragraph"><p>Finally, the loader may include a built-in validation layer that it will enable based on settings in the Developer Options menu, which would send validation errors or warnings to the system log. Drivers may be able to emit additional hardware-specific errors/warnings through this mechanism. This layer would not be enumerated through the API. This is intended to allow cooperative end-users to collect extra information about failures from unmodified applications on unmodified devices to aid triage/diagnosis of difficult-to-reproduce problems. The functionality is intentionally limited to minimize security and privacy risk.</p></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_window_system_integration">2. Window System Integration</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>TODO: Add more internal implementation details.</p></div>
+<div class="paragraph"><p>The vk_wsi_swapchin and vk_wsi_device_swapchain extensions will primarily be implemented by the platform and live in <span class="monospaced">libvulkan.so</span>. The <span class="monospaced">VkSwapchain</span> object and all interaction with <span class="monospaced">ANativeWindow</span> 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:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-style: italic"><span style="color: #9A1900">// VkNativeBufferANDROID is a vkCreateImage extension structure for creating an</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// image backed by a gralloc buffer.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// This structure is provided to vkCreateImage() in the VkImageCreateInfo</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// structure chain. Calls to vkCreateImage with this structure will happen</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// during the first call to</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   vkGetSwapChainInfoWSI(.. VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI ..)</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// The WSI implementation will allocate the number of native buffers requested</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// for the swapchain, then create a VkImage for each one.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// TBD: During swapchain re-creation (using 'oldSwapChain'), we may have to</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// defer allocation of new gralloc buffers until old buffers have been released.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// If so, the vkCreateImage calls will be deferred until the first</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// vkAcquireNextImageWSI() that would return the new image.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// When creating a gralloc-backed image, the VkImageCreateInfo will have:</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .imageType     = VK_IMAGE_TYPE_2D</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .format        = a VkFormat matching the format requested for the gralloc buffer</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .extent        = the 2D dimensions requested for the gralloc buffer</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .mipLevels     = 1</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .arraySize     = 1</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .samples       = 1</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .tiling        = VK_IMAGE_TILING_OPTIMAL</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .usage         = VkSwapChainCreateInfoWSI::imageUsageFlags</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .flags         = 0</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .sharingMode   = TBD (see below)</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .queueFamilyCount = TBD (see below)</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//   .pQueueFamilyIndices = TBD (see below)</span></span>
+
+<span style="font-weight: bold"><span style="color: #0000FF">typedef</span></span> <span style="font-weight: bold"><span style="color: #0000FF">struct</span></span> <span style="color: #FF0000">{</span>
+    <span style="color: #008080">VkStructureType</span>             sType<span style="color: #990000">;</span> <span style="font-style: italic"><span style="color: #9A1900">// must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID</span></span>
+    <span style="font-weight: bold"><span style="color: #0000FF">const</span></span> <span style="color: #009900">void</span><span style="color: #990000">*</span>                 pNext<span style="color: #990000">;</span>
+
+    <span style="font-style: italic"><span style="color: #9A1900">// Buffer handle and stride returned from gralloc alloc()</span></span>
+    <span style="color: #008080">buffer_handle_t</span>             handle<span style="color: #990000">;</span>
+    <span style="color: #009900">int</span>                         stride<span style="color: #990000">;</span>
+
+    <span style="font-style: italic"><span style="color: #9A1900">// Gralloc format and usage requested when the buffer was allocated.</span></span>
+    <span style="color: #009900">int</span>                         format<span style="color: #990000">;</span>
+    <span style="color: #009900">int</span>                         usage<span style="color: #990000">;</span>
+<span style="color: #FF0000">}</span> VkNativeBufferANDROID<span style="color: #990000">;</span></tt></pre></div></div>
+<div class="paragraph"><p>It&#8217;s not clear how we should set the <span class="monospaced">sharingMode</span>, <span class="monospaced">queueFamilyCount</span>, and <span class="monospaced">pQueueFamilyIndices</span> fields. See <a href="https://cvs.khronos.org/bugzilla/show_bug.cgi?id=14265">bug 14265</a> for details.</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-style: italic"><span style="color: #9A1900">// vkImportNativeFenceANDROID imports an externally-signalled native fence into</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// an existing VkSemaphore object.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// This function is called during vkAcquireNextImageWSI to import a native fence</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// into the VkSemaphore object provided by the application. This call puts the</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// VkSemaphore into the same "pending" state as vkQueueSignalSemaphore, so</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// queues can wait on the semaphore. The VkSemaphore signals when the underlying</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// native fence signals; if the fence has already signalled, then the semaphore</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// will be in the signalled state when this function returns.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// The driver takes ownership of the fence fd and is responsible for closing it</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// when the VkSemaphore is destroyed, when a different native fence is imported,</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// or any other condition that replaces the VkSemaphore's underlying</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// synchronization object.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// If fenceFd is -1, the VkSemaphore will be considered signalled immediately,</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// but it can still be passed to vkQueueWaitSemaphore.</span></span>
+
+VkResult <span style="color: #008080">VKAPI</span> <span style="font-weight: bold"><span style="color: #000000">vkImportNativeFenceANDROID</span></span><span style="color: #990000">(</span>
+    <span style="color: #008080">VkDevice</span>        device<span style="color: #990000">,</span>
+    <span style="color: #008080">VkSemaphore</span>     semaphore<span style="color: #990000">,</span>
+    <span style="color: #009900">int</span>             nativeFenceFd
+<span style="color: #990000">);</span></tt></pre></div></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-style: italic"><span style="color: #9A1900">// vkQueueSignalNativeFenceANDROID creates a native fence and schedules it to be</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// signalled when prior work on the queue has completed.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// This will be called during vkQueuePresentWSI on the provided queue.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// Effects are similar to vkQueueSignalSemaphore, except with a native fence</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// instead of a semaphore. Unlike vkQueueSignalSemaphore, however, this call</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// creates and returns the synchronization object that will be signalled rather</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// than having it provided as input.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// If the queue is already idle when this function is called, it is allowed but</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// not required to set *pNativeFenceFd to -1.</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">//</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// The file descriptor returned in *pNativeFenceFd is owned and will be closed</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">// by the caller.</span></span>
+
+VkResult <span style="color: #008080">VKAPI</span> <span style="font-weight: bold"><span style="color: #000000">vkQueueSignalNativeFenceANDROID</span></span><span style="color: #990000">(</span>
+    <span style="color: #008080">VkQueue</span>         queue<span style="color: #990000">,</span>
+    <span style="color: #009900">int</span><span style="color: #990000">*</span>            pNativeFenceFd<span style="color: #990000">);</span></tt></pre></div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_history">3. History</h2>
+<div class="sectionbody">
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+<strong>2015-07-08</strong> Initial version
+</p>
+</li>
+</ol></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr></div>
+<div id="footer">
+<div id="footer-text">
+Version 1<br>
+Last updated 2015-07-19 23:32:04 PDT
+</div>
+</div>
+</body>
+</html>