vulkan: Support VK_EXT_debug_report in loader and nulldrv

* Add extension to vulkan.api.
* Fix a few errors in upstream vk_ext_debug_report.h; bugs filed.
* Loader enumerates extension iff the driver supports it.
  - TODO: Also enumerate if any layers that support it are implicitly
    enabled.
  - Note extension may still be enabled if any layer supports it.
* Add loader bottom procs for the extension functions. These will call
  through to the driver version if the driver supports the extension.
* Add no-op support to nulldrv, mostly for testing the loader.

Change-Id: I092d2da56ee4c64498f8edae75e0d995478bb6f2
(cherry picked from commit a5ef7c27bc85e3628814532a32ffb9a5c33c4b73)
diff --git a/vulkan/libvulkan/debug_report.cpp b/vulkan/libvulkan/debug_report.cpp
new file mode 100644
index 0000000..fea9f18
--- /dev/null
+++ b/vulkan/libvulkan/debug_report.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "loader.h"
+
+namespace vulkan {
+
+VkResult DebugReportCallbackList::CreateCallback(
+    VkInstance instance,
+    const VkDebugReportCallbackCreateInfoEXT* create_info,
+    const VkAllocationCallbacks* allocator,
+    VkDebugReportCallbackEXT* callback) {
+    VkDebugReportCallbackEXT driver_callback;
+    VkResult result = GetDriverDispatch(instance).CreateDebugReportCallbackEXT(
+        GetDriverInstance(instance), create_info, allocator, &driver_callback);
+    if (result != VK_SUCCESS)
+        return result;
+
+    const VkAllocationCallbacks* alloc =
+        allocator ? allocator : GetAllocator(instance);
+    void* mem =
+        alloc->pfnAllocation(alloc->pUserData, sizeof(Node), alignof(Node),
+                             VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    if (!mem) {
+        GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
+            GetDriverInstance(instance), driver_callback, allocator);
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+
+    std::lock_guard<decltype(rwmutex_)> lock(rwmutex_);
+    head_.next =
+        new (mem) Node{head_.next, create_info->flags, create_info->pfnCallback,
+                       create_info->pUserData, driver_callback};
+    *callback =
+        VkDebugReportCallbackEXT(reinterpret_cast<uintptr_t>(head_.next));
+    return VK_SUCCESS;
+}
+
+void DebugReportCallbackList::DestroyCallback(
+    VkInstance instance,
+    VkDebugReportCallbackEXT callback,
+    const VkAllocationCallbacks* allocator) {
+    Node* node = reinterpret_cast<Node*>(uintptr_t(callback));
+    std::unique_lock<decltype(rwmutex_)> lock(rwmutex_);
+    Node* prev = &head_;
+    while (prev && prev->next != node)
+        prev = prev->next;
+    prev->next = node->next;
+    lock.unlock();
+
+    GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
+        GetDriverInstance(instance), node->driver_callback, allocator);
+
+    const VkAllocationCallbacks* alloc =
+        allocator ? allocator : GetAllocator(instance);
+    alloc->pfnFree(alloc->pUserData, node);
+}
+
+void DebugReportCallbackList::Message(VkDebugReportFlagsEXT flags,
+                                      VkDebugReportObjectTypeEXT object_type,
+                                      uint64_t object,
+                                      size_t location,
+                                      int32_t message_code,
+                                      const char* layer_prefix,
+                                      const char* message) {
+    std::shared_lock<decltype(rwmutex_)> lock(rwmutex_);
+    Node* node = &head_;
+    while ((node = node->next)) {
+        if ((node->flags & flags) != 0) {
+            node->callback(flags, object_type, object, location, message_code,
+                           layer_prefix, message, node->data);
+        }
+    }
+}
+
+VkResult CreateDebugReportCallbackEXT_Bottom(
+    VkInstance instance,
+    const VkDebugReportCallbackCreateInfoEXT* create_info,
+    const VkAllocationCallbacks* allocator,
+    VkDebugReportCallbackEXT* callback) {
+    return GetDebugReportCallbacks(instance).CreateCallback(
+        instance, create_info, allocator, callback);
+}
+
+void DestroyDebugReportCallbackEXT_Bottom(
+    VkInstance instance,
+    VkDebugReportCallbackEXT callback,
+    const VkAllocationCallbacks* allocator) {
+    if (callback)
+        GetDebugReportCallbacks(instance).DestroyCallback(instance, callback,
+                                                          allocator);
+}
+
+void DebugReportMessageEXT_Bottom(VkInstance instance,
+                                  VkDebugReportFlagsEXT flags,
+                                  VkDebugReportObjectTypeEXT object_type,
+                                  uint64_t object,
+                                  size_t location,
+                                  int32_t message_code,
+                                  const char* layer_prefix,
+                                  const char* message) {
+    GetDriverDispatch(instance).DebugReportMessageEXT(
+        GetDriverInstance(instance), flags, object_type, object, location,
+        message_code, layer_prefix, message);
+    GetDebugReportCallbacks(instance).Message(flags, object_type, object,
+                                              location, message_code,
+                                              layer_prefix, message);
+}
+
+}  // namespace vulkan