vulkan: Implement new vkGet*ProcAddrBehavior

The primary goal of this change is to switch to the revised GPA
behavior:
- GIPA(NULL, ..) only works for non-dispatched (global) commands
- GIPA(instance, ..) returns functions for commands that dispatch on any
  object type, and the function works for any object of the appropriate
  type if it is a child of the instance.
- GDPA(NULL, ..) returns NULL.
- GDPA(device, ..) returns a device-specific function for the command.

This change refactors/tidies many of the things it modified. Some
notable changes:
- All the loader generated code is now in dispatch.tmpl ->
  dispatch_gen.{h,cpp}, instead of two separate templates.
  - Reorganization allowed generating the dispatch table structures,
    eliminating one source of frequent bugs.
  - Removes some error-prone macro duplication.
  - Handling of extensions and special loader functions is now much
    more uniform and hopefully clearer.
- Loader top- and bottom-level functions are now consistently named with
  _Top and _Bottom suffixes, and are grouped by level in loader.cpp.
- The VkInstance and VkDevice implementations are no longer derived from
  ::VkInstance_T and ::VkDevice_T. Was more trouble than it was worth.
- Renamed 'vtbl' to 'dispatch' in most places.
- Renamed nulldrv template and generated files to match the loader
  naming pattern: null_driver.tmpl -> null_driver_gen.{h,cpp}
  - Now all the entry point prototypes are generated, instead of having
    to be updated by hand (another source of several bugs).

Change-Id: Ic263f802d0d523b18a0f00420b3a722aa04ce299
(cherry picked from commit 3cffb8e837222f413a1fe53522e2cc33366b8eeb)
diff --git a/vulkan/libvulkan/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
new file mode 100644
index 0000000..a387d81
--- /dev/null
+++ b/vulkan/libvulkan/dispatch.tmpl
@@ -0,0 +1,589 @@
+{{/*
+ * 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" $}}
+{{$ | Macro "dispatch_gen.h"   | Format (Global "clang-format") | Write "dispatch_gen.h"  }}
+{{$ | Macro "dispatch_gen.cpp" | Format (Global "clang-format") | Write "dispatch_gen.cpp"}}
+
+{{/*
+-------------------------------------------------------------------------------
+  dispatch_gen.h
+-------------------------------------------------------------------------------
+*/}}
+{{define "dispatch_gen.h"}}
+/*
+•* 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 VK_PROTOTYPES
+#define VK_USE_PLATFORM_ANDROID_KHR
+#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vulkan.h>

+namespace vulkan {

+struct InstanceDispatchTable {«
+  // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "IsInstanceDispatched" $f)}}
+      {{Macro "FunctionPtrName" $f}} {{Macro "BaseName" $f}};
+    {{end}}
+  {{end}}
+  // clang-format on
+»};

+struct DeviceDispatchTable {«
+  // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "IsDeviceDispatched" $f)}}
+      {{Macro "FunctionPtrName" $f}} {{Macro "BaseName" $f}};
+    {{end}}
+  {{end}}
+  // clang-format on
+»};

+struct DriverDispatchTable {«
+  // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "IsInstanceDispatched" $f)}}
+      {{if not (Macro "IsLoaderFunction" $f)}}
+        {{Macro "FunctionPtrName" $f}} {{Macro "BaseName" $f}};
+      {{end}}
+    {{end}}
+  {{end}}
+
+    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
+
+    {{/* TODO(jessehall): Needed by swapchain code. Figure out a better way of
+         handling this that avoids the special case. Probably should rework
+         things so the driver dispatch table has all driver functions. Probably
+         need separate instance- and device-level copies, fill in all device-
+         dispatched functions in the device-level copies only, and change
+         GetDeviceProcAddr_Bottom to look in the already-loaded driver
+         dispatch table rather than forwarding to the driver's
+         vkGetDeviceProcAddr. */}}
+    PFN_vkCreateImage CreateImage;
+    PFN_vkDestroyImage DestroyImage;
+
+    PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
+    PFN_vkAcquireImageANDROID AcquireImageANDROID;
+    PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
+  // clang-format on
+»};

+} // namespace vulkan
+¶{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  dispatch_gen.cpp
+-------------------------------------------------------------------------------
+*/}}
+{{define "dispatch_gen.cpp"}}
+/*
+•* 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 <log/log.h>
+#include <algorithm>
+#include "loader.h"

+#define UNLIKELY(expr) __builtin_expect((expr), 0)

+using namespace vulkan;

+namespace {

+struct NameProc {
+    const char* name;
+    PFN_vkVoidFunction proc;
+};

+PFN_vkVoidFunction Lookup(const char* name, const NameProc* begin, const NameProc* end) {
+    const auto& entry = std::lower_bound(
+        begin, end, name,
+        [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; });
+    if (entry == end || strcmp(entry->name, name) != 0)
+        return nullptr;
+    return entry->proc;
+}

+template <size_t N>
+PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) {
+    return Lookup(name, procs, procs + N);
+}

+const NameProc kLoaderExportProcs[] = {«
+    // clang-format off
+  {{range $f := SortBy (AllCommands $) "FunctionName"}}
+    {{if (Macro "IsFunctionSupported" $f)}}
+      {"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>({{$f.Name}})},
+    {{end}}
+  {{end}}
+    // clang-format on
+»};

+const NameProc kLoaderGlobalProcs[] = {«
+    // clang-format off
+  {{range $f := SortBy (AllCommands $) "FunctionName"}}
+    {{if and (Macro "HasLoaderTopImpl" $f) (eq (Macro "Vtbl" $f) "Global")}}
+      {"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
+        static_cast<{{Macro "FunctionPtrName" $f}}>(§
+          {{Macro "BaseName" $f}}_Top))},
+    {{end}}
+  {{end}}
+    // clang-format on
+»};

+const NameProc kLoaderTopProcs[] = {«
+    // clang-format off
+  {{range $f := SortBy (AllCommands $) "FunctionName"}}
+    {{if (Macro "HasLoaderTopImpl" $f)}}
+      {"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
+        static_cast<{{Macro "FunctionPtrName" $f}}>(§
+          {{Macro "BaseName" $f}}_Top))},
+    {{end}}
+  {{end}}
+    // clang-format on
+»};

+const NameProc kLoaderBottomProcs[] = {«
+    // clang-format off
+  {{range $f := SortBy (AllCommands $) "FunctionName"}}
+    {{if (Macro "HasLoaderBottomImpl" $f)}}
+    {"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
+        static_cast<{{Macro "FunctionPtrName" $f}}>(§
+            {{Macro "BaseName" $f}}_Bottom))},
+    {{end}}
+  {{end}}
+    // clang-format on
+»};

+struct NameOffset {
+    const char* name;
+    size_t offset;
+};

+ssize_t Lookup(const char* name,
+               const NameOffset* begin,
+               const NameOffset* end) {
+    const auto& entry = std::lower_bound(
+        begin, end, name, [](const NameOffset& e, const char* n) {
+            return strcmp(e.name, n) < 0;
+        });
+    if (entry == end || strcmp(entry->name, name) != 0)
+        return -1;
+    return static_cast<ssize_t>(entry->offset);
+}

+template <size_t N, class Table>
+PFN_vkVoidFunction Lookup(const char* name,
+                          const NameOffset (&offsets)[N],
+                          const Table& table) {
+    ssize_t offset = Lookup(name, offsets, offsets + N);
+    if (offset < 0)
+        return nullptr;
+    uintptr_t base = reinterpret_cast<uintptr_t>(&table);
+    return *reinterpret_cast<PFN_vkVoidFunction*>(base +
+                                                  static_cast<size_t>(offset));
+}

+const NameOffset kInstanceDispatchOffsets[] = {«
+  // clang-format off
+  {{range $f := SortBy (AllCommands $) "FunctionName"}}
+    {{if (Macro "IsInstanceDispatched" $f)}}
+      {"{{$f.Name}}", offsetof(InstanceDispatchTable, {{Macro "BaseName" $f}})},
+    {{end}}
+  {{end}}
+  // clang-format on
+»};

+const NameOffset kDeviceDispatchOffsets[] = {«
+  // clang-format off
+  {{range $f := SortBy (AllCommands $) "FunctionName"}}
+    {{if (Macro "IsDeviceDispatched" $f)}}
+      {"{{$f.Name}}", offsetof(DeviceDispatchTable, {{Macro "BaseName" $f}})},
+    {{end}}
+  {{end}}
+  // clang-format on
+»};

+} // anonymous namespace

+namespace vulkan {

+PFN_vkVoidFunction GetLoaderExportProcAddr(const char* name) {
+    return Lookup(name, kLoaderExportProcs);
+}

+PFN_vkVoidFunction GetLoaderGlobalProcAddr(const char* name) {
+    return Lookup(name, kLoaderGlobalProcs);
+}

+PFN_vkVoidFunction GetLoaderTopProcAddr(const char* name) {
+    return Lookup(name, kLoaderTopProcs);
+}

+PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name) {
+    return Lookup(name, kLoaderBottomProcs);
+}

+PFN_vkVoidFunction GetDispatchProcAddr(const InstanceDispatchTable& dispatch,
+                                       const char* name) {
+    return Lookup(name, kInstanceDispatchOffsets, dispatch);
+}

+PFN_vkVoidFunction GetDispatchProcAddr(const DeviceDispatchTable& dispatch,
+                                       const char* name) {
+    return Lookup(name, kDeviceDispatchOffsets, dispatch);
+}

+bool LoadInstanceDispatchTable(VkInstance instance,
+                               PFN_vkGetInstanceProcAddr get_proc_addr,
+                               InstanceDispatchTable& dispatch) {«
+    bool success = true;
+    // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "IsInstanceDispatched" $f)}}
+    dispatch.{{Macro "BaseName" $f}} = §
+        reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
+            get_proc_addr(instance, "{{$f.Name}}"));
+    if (UNLIKELY(!dispatch.{{Macro "BaseName" $f}})) {
+        ALOGE("missing instance proc: %s", "{{$f.Name}}");
+        success = false;
+    }
+    {{end}}
+  {{end}}
+    // clang-format on
+    return success;
+»}

+bool LoadDeviceDispatchTable(VkDevice device,
+                             PFN_vkGetDeviceProcAddr get_proc_addr,
+                             DeviceDispatchTable& dispatch) {«
+    bool success = true;
+    // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "IsDeviceDispatched" $f)}}
+    dispatch.{{Macro "BaseName" $f}} = §
+        reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
+            get_proc_addr(device, "{{$f.Name}}"));
+    if (UNLIKELY(!dispatch.{{Macro "BaseName" $f}})) {
+        ALOGE("missing device proc: %s", "{{$f.Name}}");
+        success = false;
+    }
+    {{end}}
+  {{end}}
+    // clang-format on
+    return success;
+»}

+bool LoadDriverDispatchTable(VkInstance instance,
+                             PFN_vkGetInstanceProcAddr get_proc_addr,
+                             DriverDispatchTable& dispatch) {«
+    bool success = true;
+    // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "IsInstanceDispatched" $f)}}
+      {{if not (Macro "IsLoaderFunction" $f)}}
+    dispatch.{{Macro "BaseName" $f}} = §
+        reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
+            get_proc_addr(instance, "{{$f.Name}}"));
+    if (UNLIKELY(!dispatch.{{Macro "BaseName" $f}})) {
+        ALOGE("missing driver proc: %s", "{{$f.Name}}");
+        success = false;
+    }
+      {{end}}
+    {{end}}
+  {{end}}
+    dispatch.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(instance, "vkGetDeviceProcAddr"));
+    if (UNLIKELY(!dispatch.GetDeviceProcAddr)) {
+        ALOGE("missing driver proc: %s", "vkGetDeviceProcAddr");
+        success = false;
+    }
+    dispatch.CreateImage = reinterpret_cast<PFN_vkCreateImage>(get_proc_addr(instance, "vkCreateImage"));
+    if (UNLIKELY(!dispatch.CreateImage)) {
+        ALOGE("missing driver proc: %s", "vkCreateImage");
+        success = false;
+    }
+    dispatch.DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(get_proc_addr(instance, "vkDestroyImage"));
+    if (UNLIKELY(!dispatch.DestroyImage)) {
+        ALOGE("missing driver proc: %s", "vkDestroyImage");
+        success = false;
+    }
+    dispatch.AcquireImageANDROID = reinterpret_cast<PFN_vkAcquireImageANDROID>(get_proc_addr(instance, "vkAcquireImageANDROID"));
+    if (UNLIKELY(!dispatch.AcquireImageANDROID)) {
+        ALOGE("missing driver proc: %s", "vkAcquireImageANDROID");
+        success = false;
+    }
+    dispatch.QueueSignalReleaseImageANDROID = reinterpret_cast<PFN_vkQueueSignalReleaseImageANDROID>(get_proc_addr(instance, "vkQueueSignalReleaseImageANDROID"));
+    if (UNLIKELY(!dispatch.QueueSignalReleaseImageANDROID)) {
+        ALOGE("missing driver proc: %s", "vkQueueSignalReleaseImageANDROID");
+        success = false;
+    }
+    // clang-format on
+    return success;
+»}

+} // namespace vulkan

+// clang-format off

+{{range $f := AllCommands $}}
+  {{if and (not (GetAnnotation $f "pfn")) (Macro "IsExported" $f)}}
+    __attribute__((visibility("default")))
+    VKAPI_ATTR {{Node "Type" $f.Return}} {{$f.Name}}({{Macro "Parameters" $f}}) {
+      {{if not (IsVoid $f.Return.Type)}}return §{{end}}
+      {{Macro "Dispatch" $f}}({{Macro "Arguments" $f}});
+    }
+    ¶
+  {{end}}
+{{end}}

+// clang-format on
+¶{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emit the dispatch lookup for a function based on its first parameter.
+-------------------------------------------------------------------------------
+*/}}
+{{define "Dispatch"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "HasLoaderTopImpl" $)}}
+    {{Macro "BaseName" $}}_Top§
+  {{else}}
+    {{$p0 := index $.CallParameters 0}}
+    GetDispatchTable({{$p0.Name}}).{{Macro "BaseName" $}}§
+  {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits a function name without the "vk" prefix.
+-------------------------------------------------------------------------------
+*/}}
+{{define "BaseName"}}
+  {{AssertType $ "Function"}}
+  {{TrimPrefix "vk" $.Name}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits a comma-separated list of C parameter names for the given command.
+-------------------------------------------------------------------------------
+*/}}
+{{define "Arguments"}}
+  {{AssertType $ "Function"}}
+
+  {{ForEach $.CallParameters "ParameterName" | JoinWith ", "}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emit "true" for supported functions that undergo table dispatch. Only global
+  functions and functions handled in the loader top without calling into
+  lower layers are not dispatched.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsInstanceDispatched"}}
+  {{AssertType $ "Function"}}
+  {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Instance")}}
+    {{if (ne $.Name "vkGetInstanceProcAddr")}}true{{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emit "true" for supported functions that can have device-specific dispatch.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsDeviceDispatched"}}
+  {{AssertType $ "Function"}}
+  {{if (Macro "IsFunctionSupported" $)}}
+    {{if eq (Macro "Vtbl" $) "Device"}}
+      {{if ne $.Name "vkGetDeviceProcAddr"}}
+        true
+      {{end}}
+    {{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emit "true" if a function is core or from a supportable extension.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsFunctionSupported"}}
+  {{AssertType $ "Function"}}
+  {{if not (GetAnnotation $ "pfn")}}
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if not $ext}}true
+    {{else if not (Macro "IsExtensionBlacklisted" $ext)}}true
+    {{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Decides whether a function should be exported from the Android Vulkan
+  library. Functions in the core API and in loader extensions are exported.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsExported"}}
+  {{AssertType $ "Function"}}
+
+  {{$ext := GetAnnotation $ "extension"}}
+  {{if $ext}}
+    {{Macro "IsLoaderExtension" $ext}}
+  {{else}}
+    true
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Reports whether an extension function is implemented entirely by the loader,
+  and not implemented by drivers.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsLoaderFunction"}}
+  {{AssertType $ "Function"}}
+
+  {{$ext := GetAnnotation $ "extension"}}
+  {{if $ext}}
+    {{Macro "IsLoaderExtension" $ext}}
+  {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emit "true" if the loader has a top-level implementation for the function
+  that should be called directly rather than dispatching to the first layer.
+-------------------------------------------------------------------------------
+*/}}
+{{define "HasLoaderTopImpl"}}
+  {{AssertType $ "Function"}}
+
+  {{/* Global functions can't be dispatched */}}
+  {{     if and (not (GetAnnotation $ "pfn")) (eq (Macro "Vtbl" $) "Global")}}true
+
+  {{/* G*PA are implemented by reading the dispatch table, not by dispatching
+       through it. */}}
+  {{else if eq $.Name "vkGetInstanceProcAddr"}}true
+  {{else if eq $.Name "vkGetDeviceProcAddr"}}true
+
+  {{/* Loader top needs to initialize dispatch for device-level dispatchable
+       objects */}}
+  {{else if eq $.Name "vkGetDeviceQueue"}}true
+  {{else if eq $.Name "vkAllocateCommandBuffers"}}true
+
+  {{/* vkDestroy for dispatchable objects needs to handle VK_NULL_HANDLE;
+       trying to dispatch through that would crash. */}}
+  {{else if eq $.Name "vkDestroyInstance"}}true
+  {{else if eq $.Name "vkDestroyDevice"}}true
+
+  {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emit "true" if the loader has a bottom-level implementation for the function
+  which terminates the dispatch chain.
+-------------------------------------------------------------------------------
+*/}}
+{{define "HasLoaderBottomImpl"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "IsFunctionSupported" $)}}
+    {{     if (eq (Macro "Vtbl" $) "Instance")}}true
+    {{else if (Macro "IsLoaderFunction" $)}}true
+    {{else if (eq $.Name "vkCreateInstance")}}true
+    {{else if (eq $.Name "vkGetDeviceProcAddr")}}true
+    {{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emit "true" if an extension is unsupportable on Android.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsExtensionBlacklisted"}}
+  {{$ext := index $.Arguments 0}}
+  {{     if eq $ext "VK_KHR_display"}}true
+  {{else if eq $ext "VK_KHR_display_swapchain"}}true
+  {{else if eq $ext "VK_KHR_xlib_surface"}}true
+  {{else if eq $ext "VK_KHR_xcb_surface"}}true
+  {{else if eq $ext "VK_KHR_wayland_surface"}}true
+  {{else if eq $ext "VK_KHR_mir_surface"}}true
+  {{else if eq $ext "VK_KHR_win32_surface"}}true
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Reports whether an extension is implemented entirely by the loader,
+  so drivers should not enumerate it.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsLoaderExtension"}}
+  {{$ext := index $.Arguments 0}}
+  {{     if eq $ext "VK_KHR_surface"}}true
+  {{else if eq $ext "VK_KHR_swapchain"}}true
+  {{else if eq $ext "VK_KHR_android_surface"}}true
+  {{end}}
+{{end}}