summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vulkan/libvulkan/dispatch.tmpl1
-rw-r--r--vulkan/libvulkan/dispatch_gen.cpp3
-rw-r--r--vulkan/libvulkan/loader.cpp442
-rw-r--r--vulkan/libvulkan/loader.h1
4 files changed, 273 insertions, 174 deletions
diff --git a/vulkan/libvulkan/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
index 054a2357a3..1a584e3733 100644
--- a/vulkan/libvulkan/dispatch.tmpl
+++ b/vulkan/libvulkan/dispatch.tmpl
@@ -560,6 +560,7 @@ bool LoadDriverDispatchTable(VkInstance instance,
objects */}}
{{else if eq $.Name "vkGetDeviceQueue"}}true
{{else if eq $.Name "vkAllocateCommandBuffers"}}true
+ {{else if eq $.Name "vkCreateDevice"}}true
{{/* vkDestroy for dispatchable objects needs to handle VK_NULL_HANDLE;
trying to dispatch through that would crash. */}}
diff --git a/vulkan/libvulkan/dispatch_gen.cpp b/vulkan/libvulkan/dispatch_gen.cpp
index 0d2d605c71..9028c3fd94 100644
--- a/vulkan/libvulkan/dispatch_gen.cpp
+++ b/vulkan/libvulkan/dispatch_gen.cpp
@@ -211,6 +211,7 @@ const NameProc kLoaderGlobalProcs[] = {
const NameProc kLoaderTopProcs[] = {
// clang-format off
{"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateCommandBuffers>(AllocateCommandBuffers_Top))},
+ {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDevice>(CreateDevice_Top))},
{"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateInstance>(CreateInstance_Top))},
{"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDevice>(DestroyDevice_Top))},
{"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyInstance>(DestroyInstance_Top))},
@@ -1401,7 +1402,7 @@ VKAPI_ATTR VkResult vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice ph
__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) {
- return GetDispatchTable(physicalDevice).CreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
+ return CreateDevice_Top(physicalDevice, pCreateInfo, pAllocator, pDevice);
}
__attribute__((visibility("default")))
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index ba5414e8fe..342fbce765 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -36,6 +36,7 @@
#include <hardware/hwvulkan.h>
#include <log/log.h>
#include <vulkan/vulkan_loader_data.h>
+#include <vulkan/vk_layer_interface.h>
// #define ENABLE_ALLOC_CALLSTACKS 1
#if ENABLE_ALLOC_CALLSTACKS
@@ -59,16 +60,6 @@ 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;
-
// ----------------------------------------------------------------------------
// Standard-library allocator that delegates to VkAllocationCallbacks.
@@ -521,6 +512,28 @@ VkResult Noop() {
return VK_SUCCESS;
}
+/*
+ * This function will return the pNext pointer of any
+ * CreateInfo extensions that are not loader extensions.
+ * This is used to skip past the loader extensions prepended
+ * to the list during CreateInstance and CreateDevice.
+ */
+void* StripCreateExtensions(const void* pNext) {
+ VkLayerInstanceCreateInfo* create_info =
+ const_cast<VkLayerInstanceCreateInfo*>(
+ static_cast<const VkLayerInstanceCreateInfo*>(pNext));
+
+ while (
+ create_info &&
+ (create_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO ||
+ create_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)) {
+ create_info = const_cast<VkLayerInstanceCreateInfo*>(
+ static_cast<const VkLayerInstanceCreateInfo*>(create_info->pNext));
+ }
+
+ return create_info;
+}
+
} // anonymous namespace
namespace vulkan {
@@ -532,9 +545,23 @@ namespace vulkan {
VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
const VkAllocationCallbacks* allocator,
VkInstance* vkinstance) {
- Instance& instance = GetDispatchParent(*vkinstance);
VkResult result;
+ VkLayerInstanceCreateInfo* chain_info =
+ const_cast<VkLayerInstanceCreateInfo*>(
+ static_cast<const VkLayerInstanceCreateInfo*>(create_info->pNext));
+ while (
+ chain_info &&
+ !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
+ chain_info->function == VK_LAYER_FUNCTION_INSTANCE)) {
+ chain_info = const_cast<VkLayerInstanceCreateInfo*>(
+ static_cast<const VkLayerInstanceCreateInfo*>(chain_info->pNext));
+ }
+ ALOG_ASSERT(chain_info != nullptr, "Missing initialization chain info!");
+
+ Instance& instance = GetDispatchParent(
+ static_cast<VkInstance>(chain_info->u.instanceInfo.instance_info));
+
// Check that all enabled extensions are supported
InstanceExtensionSet enabled_extensions;
uint32_t num_driver_extensions = 0;
@@ -572,6 +599,7 @@ VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
}
VkInstanceCreateInfo driver_create_info = *create_info;
+ driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
driver_create_info.enabledLayerCount = 0;
driver_create_info.ppEnabledLayerNames = nullptr;
driver_create_info.enabledExtensionCount = 0;
@@ -605,15 +633,14 @@ VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
hwvulkan_dispatch_t* drv_dispatch =
reinterpret_cast<hwvulkan_dispatch_t*>(instance.drv.instance);
- if (drv_dispatch->magic == HWVULKAN_DISPATCH_MAGIC) {
- // Skip setting drv_dispatch->vtbl, since we never call through it;
- // we go through instance.drv.dispatch instead.
- } else {
+ if (drv_dispatch->magic != HWVULKAN_DISPATCH_MAGIC) {
ALOGE("invalid VkInstance dispatch magic: 0x%" PRIxPTR,
drv_dispatch->magic);
DestroyInstance_Bottom(instance.handle, allocator);
return VK_ERROR_INITIALIZATION_FAILED;
}
+ // Skip setting drv_dispatch->vtbl, since we never call through it;
+ // we go through instance.drv.dispatch instead.
if (!LoadDriverDispatchTable(instance.drv.instance,
g_hwdevice->GetInstanceProcAddr,
@@ -692,6 +719,8 @@ VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
instance.drv.num_physical_devices = num_physical_devices;
instance.num_physical_devices = instance.drv.num_physical_devices;
+ *vkinstance = instance.handle;
+
return VK_SUCCESS;
}
@@ -835,31 +864,28 @@ VkResult CreateDevice_Bottom(VkPhysicalDevice gpu,
const VkDeviceCreateInfo* create_info,
const VkAllocationCallbacks* allocator,
VkDevice* device_out) {
- Instance& instance = GetDispatchParent(gpu);
- VkResult result;
-
- // FIXME(jessehall): We don't have good conventions or infrastructure yet to
- // do better than just using the instance allocator and scope for
- // everything. See b/26732122.
- if (true /*!allocator*/)
- allocator = instance.alloc;
-
- void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Device),
- alignof(Device),
- VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
- if (!mem)
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- Device* device = new (mem) Device(&instance);
-
- result = ActivateAllLayers(create_info, &instance, device);
- if (result != VK_SUCCESS) {
- DestroyDevice(device);
- return result;
+ VkLayerDeviceCreateInfo* chain_info = const_cast<VkLayerDeviceCreateInfo*>(
+ static_cast<const VkLayerDeviceCreateInfo*>(create_info->pNext));
+ while (chain_info &&
+ !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&
+ chain_info->function == VK_LAYER_FUNCTION_DEVICE)) {
+ chain_info = const_cast<VkLayerDeviceCreateInfo*>(
+ static_cast<const VkLayerDeviceCreateInfo*>(chain_info->pNext));
}
+ ALOG_ASSERT(chain_info != nullptr, "Missing initialization chain info!");
+ Instance& instance = GetDispatchParent(gpu);
size_t gpu_idx = 0;
while (instance.physical_devices[gpu_idx] != gpu)
gpu_idx++;
+ Device* device = static_cast<Device*>(chain_info->u.deviceInfo.device_info);
+ PFN_vkGetInstanceProcAddr get_instance_proc_addr =
+ chain_info->u.deviceInfo.pfnNextGetInstanceProcAddr;
+
+ VkDeviceCreateInfo driver_create_info = *create_info;
+ driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
+ driver_create_info.enabledLayerCount = 0;
+ driver_create_info.ppEnabledLayerNames = nullptr;
uint32_t num_driver_extensions = 0;
const char** driver_extensions = static_cast<const char**>(
@@ -872,6 +898,8 @@ VkResult CreateDevice_Bottom(VkPhysicalDevice gpu,
driver_extensions[num_driver_extensions++] = name;
continue;
}
+ // Add the VK_ANDROID_native_buffer extension to the list iff
+ // the VK_KHR_swapchain extension was requested
if (id == kKHR_swapchain &&
instance.physical_device_driver_extensions
[gpu_idx][kANDROID_native_buffer]) {
@@ -890,28 +918,17 @@ VkResult CreateDevice_Bottom(VkPhysicalDevice gpu,
"requested device extension '%s' not supported by loader, "
"driver, or any active layers",
name);
- DestroyDevice(device);
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
- VkDeviceCreateInfo driver_create_info = *create_info;
- driver_create_info.enabledLayerCount = 0;
- driver_create_info.ppEnabledLayerNames = nullptr;
- // TODO(jessehall): As soon as we enumerate device extensions supported by
- // the driver, we need to filter the requested extension list to those
- // supported by the driver here. Also, add the VK_ANDROID_native_buffer
- // extension to the list iff the VK_KHR_swapchain extension was requested,
- // instead of adding it unconditionally like we do now.
driver_create_info.enabledExtensionCount = num_driver_extensions;
driver_create_info.ppEnabledExtensionNames = driver_extensions;
-
VkDevice drv_device;
- result = instance.drv.dispatch.CreateDevice(gpu, &driver_create_info,
- allocator, &drv_device);
+ VkResult result = instance.drv.dispatch.CreateDevice(
+ gpu, &driver_create_info, allocator, &drv_device);
if (result != VK_SUCCESS) {
- DestroyDevice(device);
- return result;
+ return VK_ERROR_INITIALIZATION_FAILED;
}
hwvulkan_dispatch_t* drv_dispatch =
@@ -924,68 +941,15 @@ VkResult CreateDevice_Bottom(VkPhysicalDevice gpu,
instance.drv.dispatch.GetDeviceProcAddr(drv_device,
"vkDestroyDevice"));
destroy_device(drv_device, allocator);
- DestroyDevice(device);
return VK_ERROR_INITIALIZATION_FAILED;
}
+
+ // Set dispatch table for newly created Device
+ // CreateDevice_Top will fill in the details
drv_dispatch->vtbl = &device->dispatch;
device->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
instance.drv.dispatch.GetDeviceProcAddr(drv_device,
"vkGetDeviceProcAddr"));
-
- void* base_object = static_cast<void*>(drv_device);
- void* next_object = base_object;
- VkLayerLinkedListElem* next_element;
- PFN_vkGetDeviceProcAddr next_get_proc_addr = GetDeviceProcAddr_Bottom;
- Vector<VkLayerLinkedListElem> elem_list(
- CallbackAllocator<VkLayerLinkedListElem>(instance.alloc));
- try {
- elem_list.resize(device->active_layers.size());
- } catch (std::bad_alloc&) {
- ALOGE("device creation failed: out of memory");
- PFN_vkDestroyDevice destroy_device =
- reinterpret_cast<PFN_vkDestroyDevice>(
- instance.drv.dispatch.GetDeviceProcAddr(drv_device,
- "vkDestroyDevice"));
- destroy_device(drv_device, allocator);
- DestroyDevice(device);
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
-
- 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 = device->active_layers[idx].GetGetDeviceProcAddr();
- if (!next_get_proc_addr) {
- next_object = next_element->next_element;
- next_get_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
- next_element->get_proc_addr);
- }
- }
-
- // This is the magic call that initializes all the layer devices and
- // allows them to create their device_handle -> device_data mapping.
- next_get_proc_addr(static_cast<VkDevice>(next_object),
- "vkGetDeviceProcAddr");
-
- // We must create all the layer devices *before* retrieving the device
- // procaddrs, so that the layers know which extensions are enabled and
- // therefore which functions to return procaddrs for.
- PFN_vkCreateDevice create_device = reinterpret_cast<PFN_vkCreateDevice>(
- next_get_proc_addr(drv_device, "vkCreateDevice"));
- create_device(gpu, create_info, allocator, &drv_device);
-
- if (!LoadDeviceDispatchTable(static_cast<VkDevice>(base_object),
- next_get_proc_addr, device->dispatch)) {
- DestroyDevice(device);
- return VK_ERROR_INITIALIZATION_FAILED;
- }
-
*device_out = drv_device;
return VK_SUCCESS;
}
@@ -1018,16 +982,7 @@ void DestroyInstance_Bottom(VkInstance vkinstance,
PFN_vkVoidFunction GetDeviceProcAddr_Bottom(VkDevice vkdevice,
const char* name) {
if (strcmp(name, "vkCreateDevice") == 0) {
- // TODO(jessehall): Blegh, having this here is disgusting. The current
- // layer init process can't call through the instance dispatch table's
- // vkCreateDevice, because that goes through the instance layers rather
- // than through the device layers. So we need to be able to get the
- // vkCreateDevice pointer through the *device* layer chain.
- //
- // Because we've already created the driver device before calling
- // through the layer vkCreateDevice functions, the loader bottom proc
- // is a no-op.
- return reinterpret_cast<PFN_vkVoidFunction>(Noop);
+ return reinterpret_cast<PFN_vkVoidFunction>(CreateDevice_Bottom);
}
// VK_ANDROID_native_buffer should be hidden from applications and layers.
@@ -1124,48 +1079,88 @@ VkResult CreateInstance_Top(const VkInstanceCreateInfo* create_info,
return result;
}
- void* base_object = static_cast<void*>(instance->handle);
- void* next_object = base_object;
- VkLayerLinkedListElem* next_element;
- PFN_vkGetInstanceProcAddr next_get_proc_addr = GetInstanceProcAddr_Bottom;
- Vector<VkLayerLinkedListElem> elem_list(
- CallbackAllocator<VkLayerLinkedListElem>(instance->alloc));
- try {
- elem_list.resize(instance->active_layers.size());
- } catch (std::bad_alloc&) {
- ALOGE("instance creation failed: out of memory");
- DestroyInstance_Bottom(instance->handle, allocator);
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
+ uint32_t activated_layers = 0;
+ VkLayerInstanceCreateInfo chain_info;
+ VkLayerInstanceLink* layer_instance_link_info = nullptr;
+ PFN_vkGetInstanceProcAddr next_gipa = GetInstanceProcAddr_Bottom;
+ VkInstance local_instance = nullptr;
+
+ if (instance->active_layers.size() > 0) {
+ chain_info.u.pLayerInfo = nullptr;
+ chain_info.pNext = create_info->pNext;
+ chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
+ chain_info.function = VK_LAYER_FUNCTION_LINK;
+ local_create_info.pNext = &chain_info;
+
+ layer_instance_link_info = static_cast<VkLayerInstanceLink*>(alloca(
+ sizeof(VkLayerInstanceLink) * instance->active_layers.size()));
+ if (!layer_instance_link_info) {
+ ALOGE("Failed to alloc Instance objects for layers");
+ DestroyInstance_Bottom(instance->handle, allocator);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
- 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 =
- instance->active_layers[idx].GetGetInstanceProcAddr();
- if (!next_get_proc_addr) {
- next_object = next_element->next_element;
- next_get_proc_addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
- next_element->get_proc_addr);
+ /* Create instance chain of enabled layers */
+ for (auto rit = instance->active_layers.rbegin();
+ rit != instance->active_layers.rend(); ++rit) {
+ LayerRef& layer = *rit;
+ layer_instance_link_info[activated_layers].pNext =
+ chain_info.u.pLayerInfo;
+ layer_instance_link_info[activated_layers]
+ .pfnNextGetInstanceProcAddr = next_gipa;
+ chain_info.u.pLayerInfo =
+ &layer_instance_link_info[activated_layers];
+ next_gipa = layer.GetGetInstanceProcAddr();
+
+ ALOGV("Insert instance layer %s (v%u)", layer.GetName(),
+ layer.GetSpecVersion());
+
+ activated_layers++;
}
}
- // This is the magic call that initializes all the layer instances and
- // allows them to create their instance_handle -> instance_data mapping.
- next_get_proc_addr(static_cast<VkInstance>(next_object),
- "vkGetInstanceProcAddr");
+ PFN_vkCreateInstance create_instance =
+ reinterpret_cast<PFN_vkCreateInstance>(
+ next_gipa(VK_NULL_HANDLE, "vkCreateInstance"));
+ if (!create_instance) {
+ DestroyInstance_Bottom(instance->handle, allocator);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ VkLayerInstanceCreateInfo instance_create_info;
- if (!LoadInstanceDispatchTable(static_cast<VkInstance>(base_object),
- next_get_proc_addr, instance->dispatch)) {
+ instance_create_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
+ instance_create_info.function = VK_LAYER_FUNCTION_INSTANCE;
+
+ instance_create_info.u.instanceInfo.instance_info = instance;
+ instance_create_info.u.instanceInfo.pfnNextGetInstanceProcAddr = next_gipa;
+
+ instance_create_info.pNext = local_create_info.pNext;
+ local_create_info.pNext = &instance_create_info;
+
+ result = create_instance(&local_create_info, allocator, &local_instance);
+
+ if (result != VK_SUCCESS) {
DestroyInstance_Bottom(instance->handle, allocator);
+ return result;
+ }
+
+ const InstanceDispatchTable& instance_dispatch =
+ GetDispatchTable(local_instance);
+ if (!LoadInstanceDispatchTable(
+ local_instance, next_gipa,
+ const_cast<InstanceDispatchTable&>(instance_dispatch))) {
+ ALOGV("Failed to initialize instance dispatch table");
+ PFN_vkDestroyInstance destroy_instance =
+ reinterpret_cast<PFN_vkDestroyInstance>(
+ next_gipa(VK_NULL_HANDLE, "vkDestroyInstance"));
+ if (!destroy_instance) {
+ ALOGD("Loader unable to find DestroyInstance");
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ destroy_instance(local_instance, allocator);
return VK_ERROR_INITIALIZATION_FAILED;
}
+ *instance_out = local_instance;
// Force enable callback extension if required
bool enable_callback = false;
@@ -1180,30 +1175,6 @@ VkResult CreateInstance_Top(const VkInstanceCreateInfo* create_info,
}
}
- VkInstance handle = instance->handle;
- PFN_vkCreateInstance create_instance =
- reinterpret_cast<PFN_vkCreateInstance>(
- next_get_proc_addr(instance->handle, "vkCreateInstance"));
- result = create_instance(create_info, allocator, &handle);
- if (enable_callback)
- FreeAllocatedCreateInfo(local_create_info, instance->alloc);
- if (result >= 0) {
- *instance_out = instance->handle;
- } else {
- // For every layer, including the loader top and bottom layers:
- // - If a call to the next CreateInstance fails, the layer must clean
- // up anything it has successfully done so far, and propagate the
- // error upwards.
- // - If a layer successfully calls the next layer's CreateInstance, and
- // afterwards must fail for some reason, it must call the next layer's
- // DestroyInstance before returning.
- // - The layer must not call the next layer's DestroyInstance if that
- // layer's CreateInstance wasn't called, or returned failure.
-
- // On failure, CreateInstance_Bottom frees the instance struct, so it's
- // already gone at this point. Nothing to do.
- }
-
if (enable_logging) {
const VkDebugReportCallbackCreateInfoEXT callback_create_info = {
.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
@@ -1250,6 +1221,131 @@ void DestroyInstance_Top(VkInstance instance,
GetDispatchTable(instance).DestroyInstance(instance, allocator);
}
+VKAPI_ATTR
+VkResult CreateDevice_Top(VkPhysicalDevice gpu,
+ const VkDeviceCreateInfo* create_info,
+ const VkAllocationCallbacks* allocator,
+ VkDevice* device_out) {
+ Instance& instance = GetDispatchParent(gpu);
+ VkResult result;
+
+ // FIXME(jessehall): We don't have good conventions or infrastructure yet to
+ // do better than just using the instance allocator and scope for
+ // everything. See b/26732122.
+ if (true /*!allocator*/)
+ allocator = instance.alloc;
+
+ void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Device),
+ alignof(Device),
+ VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
+ if (!mem)
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ Device* device = new (mem) Device(&instance);
+
+ result = ActivateAllLayers(create_info, &instance, device);
+ if (result != VK_SUCCESS) {
+ DestroyDevice(device);
+ return result;
+ }
+
+ size_t gpu_idx = 0;
+ while (instance.physical_devices[gpu_idx] != gpu)
+ gpu_idx++;
+
+ uint32_t activated_layers = 0;
+ VkLayerDeviceCreateInfo chain_info;
+ VkLayerDeviceLink* layer_device_link_info = nullptr;
+ PFN_vkGetInstanceProcAddr next_gipa = GetInstanceProcAddr_Bottom;
+ PFN_vkGetDeviceProcAddr next_gdpa = GetDeviceProcAddr_Bottom;
+ VkDeviceCreateInfo local_create_info = *create_info;
+ VkDevice local_device = nullptr;
+
+ if (device->active_layers.size() > 0) {
+ chain_info.u.pLayerInfo = nullptr;
+ chain_info.pNext = local_create_info.pNext;
+ chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
+ chain_info.function = VK_LAYER_FUNCTION_LINK;
+ local_create_info.pNext = &chain_info;
+
+ layer_device_link_info = static_cast<VkLayerDeviceLink*>(
+ alloca(sizeof(VkLayerDeviceLink) * device->active_layers.size()));
+ if (!layer_device_link_info) {
+ ALOGE("Failed to alloc Device objects for layers");
+ DestroyDevice(device);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ /* Create device chain of enabled layers */
+ for (auto rit = device->active_layers.rbegin();
+ rit != device->active_layers.rend(); ++rit) {
+ LayerRef& layer = *rit;
+ layer_device_link_info[activated_layers].pNext =
+ chain_info.u.pLayerInfo;
+ layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr =
+ next_gdpa;
+ layer_device_link_info[activated_layers]
+ .pfnNextGetInstanceProcAddr = next_gipa;
+ chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
+
+ next_gipa = layer.GetGetInstanceProcAddr();
+ next_gdpa = layer.GetGetDeviceProcAddr();
+
+ ALOGV("Insert device layer %s (v%u)", layer.GetName(),
+ layer.GetSpecVersion());
+
+ activated_layers++;
+ }
+ }
+
+ PFN_vkCreateDevice create_device = reinterpret_cast<PFN_vkCreateDevice>(
+ next_gipa(VK_NULL_HANDLE, "vkCreateDevice"));
+ if (!create_device) {
+ ALOGE("Unable to find vkCreateDevice for driver");
+ DestroyDevice(device);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ VkLayerDeviceCreateInfo device_create_info;
+
+ device_create_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
+ device_create_info.function = VK_LAYER_FUNCTION_DEVICE;
+
+ device_create_info.u.deviceInfo.device_info = device;
+ device_create_info.u.deviceInfo.pfnNextGetInstanceProcAddr = next_gipa;
+
+ device_create_info.pNext = local_create_info.pNext;
+ local_create_info.pNext = &device_create_info;
+
+ result = create_device(gpu, &local_create_info, allocator, &local_device);
+
+ if (result != VK_SUCCESS) {
+ DestroyDevice(device);
+ return result;
+ }
+
+ // Set dispatch table for newly created Device
+ hwvulkan_dispatch_t* vulkan_dispatch =
+ reinterpret_cast<hwvulkan_dispatch_t*>(local_device);
+ vulkan_dispatch->vtbl = &device->dispatch;
+
+ const DeviceDispatchTable& device_dispatch = GetDispatchTable(local_device);
+ if (!LoadDeviceDispatchTable(
+ local_device, next_gdpa,
+ const_cast<DeviceDispatchTable&>(device_dispatch))) {
+ ALOGV("Failed to initialize device dispatch table");
+ PFN_vkDestroyDevice destroy_device =
+ reinterpret_cast<PFN_vkDestroyDevice>(
+ next_gipa(VK_NULL_HANDLE, "vkDestroyDevice"));
+ ALOG_ASSERT(destroy_device != nullptr,
+ "Loader unable to find DestroyDevice");
+ destroy_device(local_device, allocator);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ *device_out = local_device;
+
+ return VK_SUCCESS;
+}
+
PFN_vkVoidFunction GetDeviceProcAddr_Top(VkDevice device, const char* name) {
PFN_vkVoidFunction pfn;
if (!device)
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index 8d5a7581fe..8081c0eed7 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -94,6 +94,7 @@ VKAPI_ATTR void DestroyInstance_Top(VkInstance instance, const VkAllocationCallb
VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr_Top(VkDevice drv_device, const char* name);
VKAPI_ATTR void GetDeviceQueue_Top(VkDevice drv_device, uint32_t family, uint32_t index, VkQueue* out_queue);
VKAPI_ATTR VkResult AllocateCommandBuffers_Top(VkDevice device, const VkCommandBufferAllocateInfo* alloc_info, VkCommandBuffer* cmdbufs);
+VKAPI_ATTR VkResult CreateDevice_Top(VkPhysicalDevice pdev, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* device_out);
VKAPI_ATTR void DestroyDevice_Top(VkDevice drv_device, const VkAllocationCallbacks* allocator);
VKAPI_ATTR VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* vkinstance);