Add layer loading to android vulkan loader.
Change-Id: I500d248f03a14db82ce725e600aef82c115b9b35
(cherry picked from commit ad17ac2e5bec7a65e3170043eb958e5a97107bd4)
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index e178ee2..bcb1e8b 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -36,7 +36,7 @@
swapchain.cpp
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SHARED_LIBRARIES := libhardware liblog libsync
+LOCAL_SHARED_LIBRARIES := libhardware liblog libsync libcutils
LOCAL_MODULE := libvulkan
include $(BUILD_SHARED_LIBRARY)
diff --git a/vulkan/libvulkan/get_proc_addr.cpp b/vulkan/libvulkan/get_proc_addr.cpp
index 6d79972..ceb76b9 100644
--- a/vulkan/libvulkan/get_proc_addr.cpp
+++ b/vulkan/libvulkan/get_proc_addr.cpp
@@ -453,11 +453,22 @@
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");
@@ -468,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");
@@ -538,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;
diff --git a/vulkan/libvulkan/get_proc_addr.cpp.tmpl b/vulkan/libvulkan/get_proc_addr.cpp.tmpl
index 36a45d9..2e63893 100644
--- a/vulkan/libvulkan/get_proc_addr.cpp.tmpl
+++ b/vulkan/libvulkan/get_proc_addr.cpp.tmpl
@@ -201,12 +201,23 @@
}
¶
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}}"));
@@ -214,6 +225,7 @@
ALOGE("missing instance proc: %s", "{{Macro "FunctionName" $f}}");
success = false;
}
+ {{end}}
{{end}}
{{end}}
// clang-format on
@@ -221,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}}"));
@@ -234,6 +253,7 @@
ALOGE("missing device proc: %s", "{{Macro "FunctionName" $f}}");
success = false;
}
+ {{end}}
{{end}}
{{end}}
vtbl.ImportNativeFenceANDROID = reinterpret_cast<PFN_vkImportNativeFenceANDROID>(get_proc_addr(device, "vkImportNativeFenceANDROID"));
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 3ba47b3..6b223aa 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -17,6 +17,8 @@
// module header
#include "loader.h"
// standard C headers
+#include <dirent.h>
+#include <dlfcn.h>
#include <inttypes.h>
#include <malloc.h>
#include <pthread.h>
@@ -24,7 +26,12 @@
// 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>
@@ -32,9 +39,86 @@
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),
+ layer_handles(CallbackAllocator<SharedLibraryHandle>(alloc)) {
memset(&vtbl_storage, 0, sizeof(vtbl_storage));
memset(physical_devices, 0, sizeof(physical_devices));
memset(&drv.vtbl, 0, sizeof(drv.vtbl));
@@ -49,6 +133,8 @@
uint32_t num_physical_devices;
VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
+ Vector<SharedLibraryHandle> layer_handles;
+
struct Driver {
// Pointers to driver entry points. Used explicitly by the loader; not
// set as the dispatch table for any objects.
@@ -77,6 +163,7 @@
}
DeviceVtbl vtbl_storage;
const VkAllocCallbacks* alloc;
+ PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
};
// -----------------------------------------------------------------------------
@@ -141,6 +228,93 @@
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
+ // TODO: Add support for multiple layers in 1 so.
+ ALOGW_IF(count > 1,
+ "More than 1 layer per library file is not currently "
+ "supported.");
+ 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->layer_handles.push_back(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);
+}
+
// -----------------------------------------------------------------------------
// "Bottom" functions. These are called at the end of the instance dispatch
// chain.
@@ -152,6 +326,9 @@
instance->drv.vtbl.DestroyInstance) {
instance->drv.vtbl.DestroyInstance(instance->drv.vtbl.instance);
}
+ for (auto layer_handle : instance->layer_handles) {
+ dlclose(layer_handle);
+ }
const VkAllocCallbacks* alloc = instance->alloc;
instance->~VkInstance_T();
alloc->pfnFree(alloc->pUserData, instance);
@@ -170,9 +347,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;
}
@@ -319,6 +496,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);
@@ -327,19 +505,14 @@
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;
}
@@ -354,7 +527,45 @@
device->vtbl_storage.AcquireNextImageKHR = AcquireNextImageKHR;
device->vtbl_storage.QueuePresentKHR = QueuePresentKHR;
- // TODO: insert device layer entry points into device->vtbl_storage here?
+ 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.layer_handles.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);
+
+ next_get_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+ dlsym(instance.layer_handles[idx], "vkGetDeviceProcAddr"));
+ if (!next_get_proc_addr) {
+ ALOGE("Cannot find vkGetDeviceProcAddr, error is %s", 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;
@@ -418,9 +629,20 @@
// 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);
}
@@ -483,12 +705,95 @@
instance->vtbl_storage = kBottomInstanceFunctions;
instance->vtbl_storage.instance = instance;
- // TODO: Insert enabled layers into instance->dispatch_vtbl here.
+ // Scan layers
+ // TODO: Add more directories to scan
+ 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);
- // TODO: We'll want to call CreateInstance through the dispatch table
- // instead of calling the loader's terminator
+ // TODO: Add auto enabling of the layer extension
+
+ {
+ char layer_prop[PROPERTY_VALUE_MAX];
+ property_get("vulkan.layers", layer_prop, "");
+ // TODO: Find a way to enable a large number but not all of the layers
+ size_t length = strlen(layer_prop);
+ if (length == 1 && layer_prop[0] == '+') {
+ for (auto& layer : layers) {
+ LoadLayer(instance, layer.first, layer.second);
+ }
+ } else {
+ 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;
+ }
+ }
+ }
+
+ 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->layer_handles.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);
+
+ next_get_proc_addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
+ dlsym(instance->layer_handles[idx], "vkGetInstanceProcAddr"));
+ if (!next_get_proc_addr) {
+ ALOGE("Cannot find vkGetInstanceProcAddr for, error is %s",
+ 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;
+ }
+
*out_instance = instance;
- result = CreateInstanceBottom(create_info, out_instance);
+ result = instance->vtbl_storage.CreateInstance(create_info, out_instance);
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
@@ -510,6 +815,14 @@
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) {
@@ -521,6 +834,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 ||
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index d0e476c..5933eb2 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -253,9 +253,11 @@
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);
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 10fb5c9..8f65156 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -120,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
@@ -165,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,