| /* | |
| * 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. | |
| */ | |
| // The API layer of the loader defines Vulkan API and manages layers. The | |
| // entrypoints are generated and defined in api_dispatch.cpp. Most of them | |
| // simply find the dispatch table and jump. | |
| // | |
| // There are a few of them requiring manual code for things such as layer | |
| // discovery or chaining. They call into functions defined in this file. | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <algorithm> | |
| #include <mutex> | |
| #include <new> | |
| #include <utility> | |
| #include <cutils/properties.h> | |
| #include <log/log.h> | |
| #include <vulkan/vk_layer_interface.h> | |
| #include "api.h" | |
| #include "driver.h" | |
| #include "layers_extensions.h" | |
| namespace vulkan { | |
| namespace api { | |
| namespace { | |
| // Provide overridden layer names when there are implicit layers. No effect | |
| // otherwise. | |
| class OverrideLayerNames { | |
| public: | |
| OverrideLayerNames(bool is_instance, const VkAllocationCallbacks& allocator) | |
| : is_instance_(is_instance), | |
| allocator_(allocator), | |
| scope_(VK_SYSTEM_ALLOCATION_SCOPE_COMMAND), | |
| names_(nullptr), | |
| name_count_(0), | |
| implicit_layers_() { | |
| implicit_layers_.result = VK_SUCCESS; | |
| } | |
| ~OverrideLayerNames() { | |
| allocator_.pfnFree(allocator_.pUserData, names_); | |
| allocator_.pfnFree(allocator_.pUserData, implicit_layers_.elements); | |
| allocator_.pfnFree(allocator_.pUserData, implicit_layers_.name_pool); | |
| } | |
| VkResult Parse(const char* const* names, uint32_t count) { | |
| AddImplicitLayers(); | |
| const auto& arr = implicit_layers_; | |
| if (arr.result != VK_SUCCESS) | |
| return arr.result; | |
| // no need to override when there is no implicit layer | |
| if (!arr.count) | |
| return VK_SUCCESS; | |
| names_ = AllocateNameArray(arr.count + count); | |
| if (!names_) | |
| return VK_ERROR_OUT_OF_HOST_MEMORY; | |
| // add implicit layer names | |
| for (uint32_t i = 0; i < arr.count; i++) | |
| names_[i] = GetImplicitLayerName(i); | |
| name_count_ = arr.count; | |
| // add explicit layer names | |
| for (uint32_t i = 0; i < count; i++) { | |
| // ignore explicit layers that are also implicit | |
| if (IsImplicitLayer(names[i])) | |
| continue; | |
| names_[name_count_++] = names[i]; | |
| } | |
| return VK_SUCCESS; | |
| } | |
| const char* const* Names() const { return names_; } | |
| uint32_t Count() const { return name_count_; } | |
| private: | |
| struct ImplicitLayer { | |
| int priority; | |
| size_t name_offset; | |
| }; | |
| struct ImplicitLayerArray { | |
| ImplicitLayer* elements; | |
| uint32_t max_count; | |
| uint32_t count; | |
| char* name_pool; | |
| size_t max_pool_size; | |
| size_t pool_size; | |
| VkResult result; | |
| }; | |
| void AddImplicitLayers() { | |
| if (!is_instance_ || !driver::Debuggable()) | |
| return; | |
| ParseDebugVulkanLayers(); | |
| property_list(ParseDebugVulkanLayer, this); | |
| // sort by priorities | |
| auto& arr = implicit_layers_; | |
| std::sort(arr.elements, arr.elements + arr.count, | |
| [](const ImplicitLayer& a, const ImplicitLayer& b) { | |
| return (a.priority < b.priority); | |
| }); | |
| } | |
| void ParseDebugVulkanLayers() { | |
| // debug.vulkan.layers specifies colon-separated layer names | |
| char prop[PROPERTY_VALUE_MAX]; | |
| if (!property_get("debug.vulkan.layers", prop, "")) | |
| return; | |
| // assign negative/high priorities to them | |
| int prio = -PROPERTY_VALUE_MAX; | |
| const char* p = prop; | |
| const char* delim; | |
| while ((delim = strchr(p, ':'))) { | |
| if (delim > p) | |
| AddImplicitLayer(prio, p, static_cast<size_t>(delim - p)); | |
| prio++; | |
| p = delim + 1; | |
| } | |
| if (p[0] != '\0') | |
| AddImplicitLayer(prio, p, strlen(p)); | |
| } | |
| static void ParseDebugVulkanLayer(const char* key, | |
| const char* val, | |
| void* user_data) { | |
| static const char prefix[] = "debug.vulkan.layer."; | |
| const size_t prefix_len = sizeof(prefix) - 1; | |
| if (strncmp(key, prefix, prefix_len) || val[0] == '\0') | |
| return; | |
| key += prefix_len; | |
| // debug.vulkan.layer.<priority> | |
| int priority = -1; | |
| if (key[0] >= '0' && key[0] <= '9') | |
| priority = atoi(key); | |
| if (priority < 0) { | |
| ALOGW("Ignored implicit layer %s with invalid priority %s", val, | |
| key); | |
| return; | |
| } | |
| OverrideLayerNames& override_layers = | |
| *reinterpret_cast<OverrideLayerNames*>(user_data); | |
| override_layers.AddImplicitLayer(priority, val, strlen(val)); | |
| } | |
| void AddImplicitLayer(int priority, const char* name, size_t len) { | |
| if (!GrowImplicitLayerArray(1, 0)) | |
| return; | |
| auto& arr = implicit_layers_; | |
| auto& layer = arr.elements[arr.count++]; | |
| layer.priority = priority; | |
| layer.name_offset = AddImplicitLayerName(name, len); | |
| ALOGV("Added implicit layer %s", GetImplicitLayerName(arr.count - 1)); | |
| } | |
| size_t AddImplicitLayerName(const char* name, size_t len) { | |
| if (!GrowImplicitLayerArray(0, len + 1)) | |
| return 0; | |
| // add the name to the pool | |
| auto& arr = implicit_layers_; | |
| size_t offset = arr.pool_size; | |
| char* dst = arr.name_pool + offset; | |
| std::copy(name, name + len, dst); | |
| dst[len] = '\0'; | |
| arr.pool_size += len + 1; | |
| return offset; | |
| } | |
| bool GrowImplicitLayerArray(uint32_t layer_count, size_t name_size) { | |
| const uint32_t initial_max_count = 16; | |
| const size_t initial_max_pool_size = 512; | |
| auto& arr = implicit_layers_; | |
| // grow the element array if needed | |
| while (arr.count + layer_count > arr.max_count) { | |
| uint32_t new_max_count = | |
| (arr.max_count) ? (arr.max_count << 1) : initial_max_count; | |
| void* new_mem = nullptr; | |
| if (new_max_count > arr.max_count) { | |
| new_mem = allocator_.pfnReallocation( | |
| allocator_.pUserData, arr.elements, | |
| sizeof(ImplicitLayer) * new_max_count, | |
| alignof(ImplicitLayer), scope_); | |
| } | |
| if (!new_mem) { | |
| arr.result = VK_ERROR_OUT_OF_HOST_MEMORY; | |
| arr.count = 0; | |
| return false; | |
| } | |
| arr.elements = reinterpret_cast<ImplicitLayer*>(new_mem); | |
| arr.max_count = new_max_count; | |
| } | |
| // grow the name pool if needed | |
| while (arr.pool_size + name_size > arr.max_pool_size) { | |
| size_t new_max_pool_size = (arr.max_pool_size) | |
| ? (arr.max_pool_size << 1) | |
| : initial_max_pool_size; | |
| void* new_mem = nullptr; | |
| if (new_max_pool_size > arr.max_pool_size) { | |
| new_mem = allocator_.pfnReallocation( | |
| allocator_.pUserData, arr.name_pool, new_max_pool_size, | |
| alignof(char), scope_); | |
| } | |
| if (!new_mem) { | |
| arr.result = VK_ERROR_OUT_OF_HOST_MEMORY; | |
| arr.pool_size = 0; | |
| return false; | |
| } | |
| arr.name_pool = reinterpret_cast<char*>(new_mem); | |
| arr.max_pool_size = new_max_pool_size; | |
| } | |
| return true; | |
| } | |
| const char* GetImplicitLayerName(uint32_t index) const { | |
| const auto& arr = implicit_layers_; | |
| // this may return nullptr when arr.result is not VK_SUCCESS | |
| return implicit_layers_.name_pool + arr.elements[index].name_offset; | |
| } | |
| bool IsImplicitLayer(const char* name) const { | |
| const auto& arr = implicit_layers_; | |
| for (uint32_t i = 0; i < arr.count; i++) { | |
| if (strcmp(name, GetImplicitLayerName(i)) == 0) | |
| return true; | |
| } | |
| return false; | |
| } | |
| const char** AllocateNameArray(uint32_t count) const { | |
| return reinterpret_cast<const char**>(allocator_.pfnAllocation( | |
| allocator_.pUserData, sizeof(const char*) * count, | |
| alignof(const char*), scope_)); | |
| } | |
| const bool is_instance_; | |
| const VkAllocationCallbacks& allocator_; | |
| const VkSystemAllocationScope scope_; | |
| const char** names_; | |
| uint32_t name_count_; | |
| ImplicitLayerArray implicit_layers_; | |
| }; | |
| // Provide overridden extension names when there are implicit extensions. | |
| // No effect otherwise. | |
| // | |
| // This is used only to enable VK_EXT_debug_report. | |
| class OverrideExtensionNames { | |
| public: | |
| OverrideExtensionNames(bool is_instance, | |
| const VkAllocationCallbacks& allocator) | |
| : is_instance_(is_instance), | |
| allocator_(allocator), | |
| scope_(VK_SYSTEM_ALLOCATION_SCOPE_COMMAND), | |
| names_(nullptr), | |
| name_count_(0), | |
| install_debug_callback_(false) {} | |
| ~OverrideExtensionNames() { | |
| allocator_.pfnFree(allocator_.pUserData, names_); | |
| } | |
| VkResult Parse(const char* const* names, uint32_t count) { | |
| // this is only for debug.vulkan.enable_callback | |
| if (!EnableDebugCallback()) | |
| return VK_SUCCESS; | |
| names_ = AllocateNameArray(count + 1); | |
| if (!names_) | |
| return VK_ERROR_OUT_OF_HOST_MEMORY; | |
| std::copy(names, names + count, names_); | |
| name_count_ = count; | |
| names_[name_count_++] = "VK_EXT_debug_report"; | |
| install_debug_callback_ = true; | |
| return VK_SUCCESS; | |
| } | |
| const char* const* Names() const { return names_; } | |
| uint32_t Count() const { return name_count_; } | |
| bool InstallDebugCallback() const { return install_debug_callback_; } | |
| private: | |
| bool EnableDebugCallback() const { | |
| return (is_instance_ && driver::Debuggable() && | |
| property_get_bool("debug.vulkan.enable_callback", false)); | |
| } | |
| const char** AllocateNameArray(uint32_t count) const { | |
| return reinterpret_cast<const char**>(allocator_.pfnAllocation( | |
| allocator_.pUserData, sizeof(const char*) * count, | |
| alignof(const char*), scope_)); | |
| } | |
| const bool is_instance_; | |
| const VkAllocationCallbacks& allocator_; | |
| const VkSystemAllocationScope scope_; | |
| const char** names_; | |
| uint32_t name_count_; | |
| bool install_debug_callback_; | |
| }; | |
| // vkCreateInstance and vkCreateDevice helpers with support for layer | |
| // chaining. | |
| class LayerChain { | |
| public: | |
| struct ActiveLayer { | |
| LayerRef ref; | |
| union { | |
| VkLayerInstanceLink instance_link; | |
| VkLayerDeviceLink device_link; | |
| }; | |
| }; | |
| static VkResult CreateInstance(const VkInstanceCreateInfo* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkInstance* instance_out); | |
| static VkResult CreateDevice(VkPhysicalDevice physical_dev, | |
| const VkDeviceCreateInfo* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkDevice* dev_out); | |
| static void DestroyInstance(VkInstance instance, | |
| const VkAllocationCallbacks* allocator); | |
| static void DestroyDevice(VkDevice dev, | |
| const VkAllocationCallbacks* allocator); | |
| static const ActiveLayer* GetActiveLayers(VkPhysicalDevice physical_dev, | |
| uint32_t& count); | |
| private: | |
| LayerChain(bool is_instance, | |
| const driver::DebugReportLogger& logger, | |
| const VkAllocationCallbacks& allocator); | |
| ~LayerChain(); | |
| VkResult ActivateLayers(const char* const* layer_names, | |
| uint32_t layer_count, | |
| const char* const* extension_names, | |
| uint32_t extension_count); | |
| VkResult ActivateLayers(VkPhysicalDevice physical_dev, | |
| const char* const* layer_names, | |
| uint32_t layer_count, | |
| const char* const* extension_names, | |
| uint32_t extension_count); | |
| ActiveLayer* AllocateLayerArray(uint32_t count) const; | |
| VkResult LoadLayer(ActiveLayer& layer, const char* name); | |
| void SetupLayerLinks(); | |
| bool Empty() const; | |
| void ModifyCreateInfo(VkInstanceCreateInfo& info); | |
| void ModifyCreateInfo(VkDeviceCreateInfo& info); | |
| VkResult Create(const VkInstanceCreateInfo* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkInstance* instance_out); | |
| VkResult Create(VkPhysicalDevice physical_dev, | |
| const VkDeviceCreateInfo* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkDevice* dev_out); | |
| VkResult ValidateExtensions(const char* const* extension_names, | |
| uint32_t extension_count); | |
| VkResult ValidateExtensions(VkPhysicalDevice physical_dev, | |
| const char* const* extension_names, | |
| uint32_t extension_count); | |
| VkExtensionProperties* AllocateDriverExtensionArray(uint32_t count) const; | |
| bool IsLayerExtension(const char* name) const; | |
| bool IsDriverExtension(const char* name) const; | |
| template <typename DataType> | |
| void StealLayers(DataType& data); | |
| static void DestroyLayers(ActiveLayer* layers, | |
| uint32_t count, | |
| const VkAllocationCallbacks& allocator); | |
| static VKAPI_ATTR VkResult SetInstanceLoaderData(VkInstance instance, | |
| void* object); | |
| static VKAPI_ATTR VkResult SetDeviceLoaderData(VkDevice device, | |
| void* object); | |
| static VKAPI_ATTR VkBool32 | |
| DebugReportCallback(VkDebugReportFlagsEXT flags, | |
| VkDebugReportObjectTypeEXT obj_type, | |
| uint64_t obj, | |
| size_t location, | |
| int32_t msg_code, | |
| const char* layer_prefix, | |
| const char* msg, | |
| void* user_data); | |
| const bool is_instance_; | |
| const driver::DebugReportLogger& logger_; | |
| const VkAllocationCallbacks& allocator_; | |
| OverrideLayerNames override_layers_; | |
| OverrideExtensionNames override_extensions_; | |
| ActiveLayer* layers_; | |
| uint32_t layer_count_; | |
| PFN_vkGetInstanceProcAddr get_instance_proc_addr_; | |
| PFN_vkGetDeviceProcAddr get_device_proc_addr_; | |
| union { | |
| VkLayerInstanceCreateInfo instance_chain_info_[2]; | |
| VkLayerDeviceCreateInfo device_chain_info_[2]; | |
| }; | |
| VkExtensionProperties* driver_extensions_; | |
| uint32_t driver_extension_count_; | |
| std::bitset<driver::ProcHook::EXTENSION_COUNT> enabled_extensions_; | |
| }; | |
| LayerChain::LayerChain(bool is_instance, | |
| const driver::DebugReportLogger& logger, | |
| const VkAllocationCallbacks& allocator) | |
| : is_instance_(is_instance), | |
| logger_(logger), | |
| allocator_(allocator), | |
| override_layers_(is_instance, allocator), | |
| override_extensions_(is_instance, allocator), | |
| layers_(nullptr), | |
| layer_count_(0), | |
| get_instance_proc_addr_(nullptr), | |
| get_device_proc_addr_(nullptr), | |
| driver_extensions_(nullptr), | |
| driver_extension_count_(0) { | |
| enabled_extensions_.set(driver::ProcHook::EXTENSION_CORE); | |
| } | |
| LayerChain::~LayerChain() { | |
| allocator_.pfnFree(allocator_.pUserData, driver_extensions_); | |
| DestroyLayers(layers_, layer_count_, allocator_); | |
| } | |
| VkResult LayerChain::ActivateLayers(const char* const* layer_names, | |
| uint32_t layer_count, | |
| const char* const* extension_names, | |
| uint32_t extension_count) { | |
| VkResult result = override_layers_.Parse(layer_names, layer_count); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| result = override_extensions_.Parse(extension_names, extension_count); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| if (override_layers_.Count()) { | |
| layer_names = override_layers_.Names(); | |
| layer_count = override_layers_.Count(); | |
| } | |
| if (!layer_count) { | |
| // point head of chain to the driver | |
| get_instance_proc_addr_ = driver::GetInstanceProcAddr; | |
| return VK_SUCCESS; | |
| } | |
| layers_ = AllocateLayerArray(layer_count); | |
| if (!layers_) | |
| return VK_ERROR_OUT_OF_HOST_MEMORY; | |
| // load layers | |
| for (uint32_t i = 0; i < layer_count; i++) { | |
| result = LoadLayer(layers_[i], layer_names[i]); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| // count loaded layers for proper destructions on errors | |
| layer_count_++; | |
| } | |
| SetupLayerLinks(); | |
| return VK_SUCCESS; | |
| } | |
| VkResult LayerChain::ActivateLayers(VkPhysicalDevice physical_dev, | |
| const char* const* layer_names, | |
| uint32_t layer_count, | |
| const char* const* extension_names, | |
| uint32_t extension_count) { | |
| uint32_t instance_layer_count; | |
| const ActiveLayer* instance_layers = | |
| GetActiveLayers(physical_dev, instance_layer_count); | |
| // log a message if the application device layer array is not empty nor an | |
| // exact match of the instance layer array. | |
| if (layer_count) { | |
| bool exact_match = (instance_layer_count == layer_count); | |
| if (exact_match) { | |
| for (uint32_t i = 0; i < instance_layer_count; i++) { | |
| const Layer& l = *instance_layers[i].ref; | |
| if (strcmp(GetLayerProperties(l).layerName, layer_names[i])) { | |
| exact_match = false; | |
| break; | |
| } | |
| } | |
| } | |
| if (!exact_match) { | |
| logger_.Warn(physical_dev, | |
| "Device layers disagree with instance layers and are " | |
| "overridden by instance layers"); | |
| } | |
| } | |
| VkResult result = | |
| override_extensions_.Parse(extension_names, extension_count); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| if (!instance_layer_count) { | |
| // point head of chain to the driver | |
| get_instance_proc_addr_ = driver::GetInstanceProcAddr; | |
| get_device_proc_addr_ = driver::GetDeviceProcAddr; | |
| return VK_SUCCESS; | |
| } | |
| layers_ = AllocateLayerArray(instance_layer_count); | |
| if (!layers_) | |
| return VK_ERROR_OUT_OF_HOST_MEMORY; | |
| for (uint32_t i = 0; i < instance_layer_count; i++) { | |
| const Layer& l = *instance_layers[i].ref; | |
| // no need to and cannot chain non-global layers | |
| if (!IsLayerGlobal(l)) | |
| continue; | |
| // this never fails | |
| new (&layers_[layer_count_++]) ActiveLayer{GetLayerRef(l), {}}; | |
| } | |
| // this may happen when all layers are non-global ones | |
| if (!layer_count_) { | |
| get_instance_proc_addr_ = driver::GetInstanceProcAddr; | |
| get_device_proc_addr_ = driver::GetDeviceProcAddr; | |
| return VK_SUCCESS; | |
| } | |
| SetupLayerLinks(); | |
| return VK_SUCCESS; | |
| } | |
| LayerChain::ActiveLayer* LayerChain::AllocateLayerArray(uint32_t count) const { | |
| VkSystemAllocationScope scope = (is_instance_) | |
| ? VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE | |
| : VK_SYSTEM_ALLOCATION_SCOPE_COMMAND; | |
| return reinterpret_cast<ActiveLayer*>(allocator_.pfnAllocation( | |
| allocator_.pUserData, sizeof(ActiveLayer) * count, alignof(ActiveLayer), | |
| scope)); | |
| } | |
| VkResult LayerChain::LoadLayer(ActiveLayer& layer, const char* name) { | |
| const Layer* l = FindLayer(name); | |
| if (!l) { | |
| logger_.Err(VK_NULL_HANDLE, "Failed to find layer %s", name); | |
| return VK_ERROR_LAYER_NOT_PRESENT; | |
| } | |
| new (&layer) ActiveLayer{GetLayerRef(*l), {}}; | |
| if (!layer.ref) { | |
| ALOGW("Failed to open layer %s", name); | |
| layer.ref.~LayerRef(); | |
| return VK_ERROR_LAYER_NOT_PRESENT; | |
| } | |
| ALOGI("Loaded layer %s", name); | |
| return VK_SUCCESS; | |
| } | |
| void LayerChain::SetupLayerLinks() { | |
| if (is_instance_) { | |
| for (uint32_t i = 0; i < layer_count_; i++) { | |
| ActiveLayer& layer = layers_[i]; | |
| // point head of chain to the first layer | |
| if (i == 0) | |
| get_instance_proc_addr_ = layer.ref.GetGetInstanceProcAddr(); | |
| // point tail of chain to the driver | |
| if (i == layer_count_ - 1) { | |
| layer.instance_link.pNext = nullptr; | |
| layer.instance_link.pfnNextGetInstanceProcAddr = | |
| driver::GetInstanceProcAddr; | |
| break; | |
| } | |
| const ActiveLayer& next = layers_[i + 1]; | |
| // const_cast as some naughty layers want to modify our links! | |
| layer.instance_link.pNext = | |
| const_cast<VkLayerInstanceLink*>(&next.instance_link); | |
| layer.instance_link.pfnNextGetInstanceProcAddr = | |
| next.ref.GetGetInstanceProcAddr(); | |
| } | |
| } else { | |
| for (uint32_t i = 0; i < layer_count_; i++) { | |
| ActiveLayer& layer = layers_[i]; | |
| // point head of chain to the first layer | |
| if (i == 0) { | |
| get_instance_proc_addr_ = layer.ref.GetGetInstanceProcAddr(); | |
| get_device_proc_addr_ = layer.ref.GetGetDeviceProcAddr(); | |
| } | |
| // point tail of chain to the driver | |
| if (i == layer_count_ - 1) { | |
| layer.device_link.pNext = nullptr; | |
| layer.device_link.pfnNextGetInstanceProcAddr = | |
| driver::GetInstanceProcAddr; | |
| layer.device_link.pfnNextGetDeviceProcAddr = | |
| driver::GetDeviceProcAddr; | |
| break; | |
| } | |
| const ActiveLayer& next = layers_[i + 1]; | |
| // const_cast as some naughty layers want to modify our links! | |
| layer.device_link.pNext = | |
| const_cast<VkLayerDeviceLink*>(&next.device_link); | |
| layer.device_link.pfnNextGetInstanceProcAddr = | |
| next.ref.GetGetInstanceProcAddr(); | |
| layer.device_link.pfnNextGetDeviceProcAddr = | |
| next.ref.GetGetDeviceProcAddr(); | |
| } | |
| } | |
| } | |
| bool LayerChain::Empty() const { | |
| return (!layer_count_ && !override_layers_.Count() && | |
| !override_extensions_.Count()); | |
| } | |
| void LayerChain::ModifyCreateInfo(VkInstanceCreateInfo& info) { | |
| if (layer_count_) { | |
| auto& link_info = instance_chain_info_[1]; | |
| link_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; | |
| link_info.pNext = info.pNext; | |
| link_info.function = VK_LAYER_FUNCTION_LINK; | |
| link_info.u.pLayerInfo = &layers_[0].instance_link; | |
| auto& cb_info = instance_chain_info_[0]; | |
| cb_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; | |
| cb_info.pNext = &link_info; | |
| cb_info.function = VK_LAYER_FUNCTION_DATA_CALLBACK; | |
| cb_info.u.pfnSetInstanceLoaderData = SetInstanceLoaderData; | |
| info.pNext = &cb_info; | |
| } | |
| if (override_layers_.Count()) { | |
| info.enabledLayerCount = override_layers_.Count(); | |
| info.ppEnabledLayerNames = override_layers_.Names(); | |
| } | |
| if (override_extensions_.Count()) { | |
| info.enabledExtensionCount = override_extensions_.Count(); | |
| info.ppEnabledExtensionNames = override_extensions_.Names(); | |
| } | |
| } | |
| void LayerChain::ModifyCreateInfo(VkDeviceCreateInfo& info) { | |
| if (layer_count_) { | |
| auto& link_info = device_chain_info_[1]; | |
| link_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; | |
| link_info.pNext = info.pNext; | |
| link_info.function = VK_LAYER_FUNCTION_LINK; | |
| link_info.u.pLayerInfo = &layers_[0].device_link; | |
| auto& cb_info = device_chain_info_[0]; | |
| cb_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; | |
| cb_info.pNext = &link_info; | |
| cb_info.function = VK_LAYER_FUNCTION_DATA_CALLBACK; | |
| cb_info.u.pfnSetDeviceLoaderData = SetDeviceLoaderData; | |
| info.pNext = &cb_info; | |
| } | |
| if (override_layers_.Count()) { | |
| info.enabledLayerCount = override_layers_.Count(); | |
| info.ppEnabledLayerNames = override_layers_.Names(); | |
| } | |
| if (override_extensions_.Count()) { | |
| info.enabledExtensionCount = override_extensions_.Count(); | |
| info.ppEnabledExtensionNames = override_extensions_.Names(); | |
| } | |
| } | |
| VkResult LayerChain::Create(const VkInstanceCreateInfo* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkInstance* instance_out) { | |
| VkResult result = ValidateExtensions(create_info->ppEnabledExtensionNames, | |
| create_info->enabledExtensionCount); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| // call down the chain | |
| PFN_vkCreateInstance create_instance = | |
| reinterpret_cast<PFN_vkCreateInstance>( | |
| get_instance_proc_addr_(VK_NULL_HANDLE, "vkCreateInstance")); | |
| VkInstance instance; | |
| result = create_instance(create_info, allocator, &instance); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| // initialize InstanceData | |
| InstanceData& data = GetData(instance); | |
| if (!InitDispatchTable(instance, get_instance_proc_addr_, | |
| enabled_extensions_)) { | |
| if (data.dispatch.DestroyInstance) | |
| data.dispatch.DestroyInstance(instance, allocator); | |
| return VK_ERROR_INITIALIZATION_FAILED; | |
| } | |
| // install debug report callback | |
| if (override_extensions_.InstallDebugCallback()) { | |
| PFN_vkCreateDebugReportCallbackEXT create_debug_report_callback = | |
| reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>( | |
| get_instance_proc_addr_(instance, | |
| "vkCreateDebugReportCallbackEXT")); | |
| data.destroy_debug_callback = | |
| reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>( | |
| get_instance_proc_addr_(instance, | |
| "vkDestroyDebugReportCallbackEXT")); | |
| if (!create_debug_report_callback || !data.destroy_debug_callback) { | |
| ALOGE("Broken VK_EXT_debug_report support"); | |
| data.dispatch.DestroyInstance(instance, allocator); | |
| return VK_ERROR_INITIALIZATION_FAILED; | |
| } | |
| VkDebugReportCallbackCreateInfoEXT debug_callback_info = {}; | |
| debug_callback_info.sType = | |
| VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; | |
| debug_callback_info.flags = | |
| VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; | |
| debug_callback_info.pfnCallback = DebugReportCallback; | |
| VkDebugReportCallbackEXT debug_callback; | |
| result = create_debug_report_callback(instance, &debug_callback_info, | |
| nullptr, &debug_callback); | |
| if (result != VK_SUCCESS) { | |
| ALOGE("Failed to install debug report callback"); | |
| data.dispatch.DestroyInstance(instance, allocator); | |
| return VK_ERROR_INITIALIZATION_FAILED; | |
| } | |
| data.debug_callback = debug_callback; | |
| ALOGI("Installed debug report callback"); | |
| } | |
| StealLayers(data); | |
| *instance_out = instance; | |
| return VK_SUCCESS; | |
| } | |
| VkResult LayerChain::Create(VkPhysicalDevice physical_dev, | |
| const VkDeviceCreateInfo* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkDevice* dev_out) { | |
| VkResult result = | |
| ValidateExtensions(physical_dev, create_info->ppEnabledExtensionNames, | |
| create_info->enabledExtensionCount); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| // call down the chain | |
| PFN_vkCreateDevice create_device = | |
| GetData(physical_dev).dispatch.CreateDevice; | |
| VkDevice dev; | |
| result = create_device(physical_dev, create_info, allocator, &dev); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| // initialize DeviceData | |
| DeviceData& data = GetData(dev); | |
| if (!InitDispatchTable(dev, get_device_proc_addr_, enabled_extensions_)) { | |
| if (data.dispatch.DestroyDevice) | |
| data.dispatch.DestroyDevice(dev, allocator); | |
| return VK_ERROR_INITIALIZATION_FAILED; | |
| } | |
| // no StealLayers so that active layers are destroyed with this | |
| // LayerChain | |
| *dev_out = dev; | |
| return VK_SUCCESS; | |
| } | |
| VkResult LayerChain::ValidateExtensions(const char* const* extension_names, | |
| uint32_t extension_count) { | |
| if (!extension_count) | |
| return VK_SUCCESS; | |
| // query driver instance extensions | |
| uint32_t count; | |
| VkResult result = | |
| EnumerateInstanceExtensionProperties(nullptr, &count, nullptr); | |
| if (result == VK_SUCCESS && count) { | |
| driver_extensions_ = AllocateDriverExtensionArray(count); | |
| result = (driver_extensions_) ? EnumerateInstanceExtensionProperties( | |
| nullptr, &count, driver_extensions_) | |
| : VK_ERROR_OUT_OF_HOST_MEMORY; | |
| } | |
| if (result != VK_SUCCESS) | |
| return result; | |
| driver_extension_count_ = count; | |
| for (uint32_t i = 0; i < extension_count; i++) { | |
| const char* name = extension_names[i]; | |
| if (!IsLayerExtension(name) && !IsDriverExtension(name)) { | |
| logger_.Err(VK_NULL_HANDLE, | |
| "Failed to enable missing instance extension %s", name); | |
| return VK_ERROR_EXTENSION_NOT_PRESENT; | |
| } | |
| auto ext_bit = driver::GetProcHookExtension(name); | |
| if (ext_bit != driver::ProcHook::EXTENSION_UNKNOWN) | |
| enabled_extensions_.set(ext_bit); | |
| } | |
| return VK_SUCCESS; | |
| } | |
| VkResult LayerChain::ValidateExtensions(VkPhysicalDevice physical_dev, | |
| const char* const* extension_names, | |
| uint32_t extension_count) { | |
| if (!extension_count) | |
| return VK_SUCCESS; | |
| // query driver device extensions | |
| uint32_t count; | |
| VkResult result = EnumerateDeviceExtensionProperties(physical_dev, nullptr, | |
| &count, nullptr); | |
| if (result == VK_SUCCESS && count) { | |
| driver_extensions_ = AllocateDriverExtensionArray(count); | |
| result = (driver_extensions_) | |
| ? EnumerateDeviceExtensionProperties( | |
| physical_dev, nullptr, &count, driver_extensions_) | |
| : VK_ERROR_OUT_OF_HOST_MEMORY; | |
| } | |
| if (result != VK_SUCCESS) | |
| return result; | |
| driver_extension_count_ = count; | |
| for (uint32_t i = 0; i < extension_count; i++) { | |
| const char* name = extension_names[i]; | |
| if (!IsLayerExtension(name) && !IsDriverExtension(name)) { | |
| logger_.Err(physical_dev, | |
| "Failed to enable missing device extension %s", name); | |
| return VK_ERROR_EXTENSION_NOT_PRESENT; | |
| } | |
| auto ext_bit = driver::GetProcHookExtension(name); | |
| if (ext_bit != driver::ProcHook::EXTENSION_UNKNOWN) | |
| enabled_extensions_.set(ext_bit); | |
| } | |
| return VK_SUCCESS; | |
| } | |
| VkExtensionProperties* LayerChain::AllocateDriverExtensionArray( | |
| uint32_t count) const { | |
| return reinterpret_cast<VkExtensionProperties*>(allocator_.pfnAllocation( | |
| allocator_.pUserData, sizeof(VkExtensionProperties) * count, | |
| alignof(VkExtensionProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); | |
| } | |
| bool LayerChain::IsLayerExtension(const char* name) const { | |
| if (is_instance_) { | |
| for (uint32_t i = 0; i < layer_count_; i++) { | |
| const ActiveLayer& layer = layers_[i]; | |
| if (FindLayerInstanceExtension(*layer.ref, name)) | |
| return true; | |
| } | |
| } else { | |
| for (uint32_t i = 0; i < layer_count_; i++) { | |
| const ActiveLayer& layer = layers_[i]; | |
| if (FindLayerDeviceExtension(*layer.ref, name)) | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| bool LayerChain::IsDriverExtension(const char* name) const { | |
| for (uint32_t i = 0; i < driver_extension_count_; i++) { | |
| if (strcmp(driver_extensions_[i].extensionName, name) == 0) | |
| return true; | |
| } | |
| return false; | |
| } | |
| template <typename DataType> | |
| void LayerChain::StealLayers(DataType& data) { | |
| data.layers = layers_; | |
| data.layer_count = layer_count_; | |
| layers_ = nullptr; | |
| layer_count_ = 0; | |
| } | |
| void LayerChain::DestroyLayers(ActiveLayer* layers, | |
| uint32_t count, | |
| const VkAllocationCallbacks& allocator) { | |
| for (uint32_t i = 0; i < count; i++) | |
| layers[i].ref.~LayerRef(); | |
| allocator.pfnFree(allocator.pUserData, layers); | |
| } | |
| VkResult LayerChain::SetInstanceLoaderData(VkInstance instance, void* object) { | |
| driver::InstanceDispatchable dispatchable = | |
| reinterpret_cast<driver::InstanceDispatchable>(object); | |
| return (driver::SetDataInternal(dispatchable, &driver::GetData(instance))) | |
| ? VK_SUCCESS | |
| : VK_ERROR_INITIALIZATION_FAILED; | |
| } | |
| VkResult LayerChain::SetDeviceLoaderData(VkDevice device, void* object) { | |
| driver::DeviceDispatchable dispatchable = | |
| reinterpret_cast<driver::DeviceDispatchable>(object); | |
| return (driver::SetDataInternal(dispatchable, &driver::GetData(device))) | |
| ? VK_SUCCESS | |
| : VK_ERROR_INITIALIZATION_FAILED; | |
| } | |
| VkBool32 LayerChain::DebugReportCallback(VkDebugReportFlagsEXT flags, | |
| VkDebugReportObjectTypeEXT obj_type, | |
| uint64_t obj, | |
| size_t location, | |
| int32_t msg_code, | |
| const char* layer_prefix, | |
| const char* msg, | |
| void* user_data) { | |
| int prio; | |
| if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) | |
| prio = ANDROID_LOG_ERROR; | |
| else if (flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | | |
| VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) | |
| prio = ANDROID_LOG_WARN; | |
| else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) | |
| prio = ANDROID_LOG_INFO; | |
| else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) | |
| prio = ANDROID_LOG_DEBUG; | |
| else | |
| prio = ANDROID_LOG_UNKNOWN; | |
| LOG_PRI(prio, LOG_TAG, "[%s] Code %d : %s", layer_prefix, msg_code, msg); | |
| (void)obj_type; | |
| (void)obj; | |
| (void)location; | |
| (void)user_data; | |
| return false; | |
| } | |
| VkResult LayerChain::CreateInstance(const VkInstanceCreateInfo* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkInstance* instance_out) { | |
| const driver::DebugReportLogger logger(*create_info); | |
| LayerChain chain(true, logger, | |
| (allocator) ? *allocator : driver::GetDefaultAllocator()); | |
| VkResult result = chain.ActivateLayers(create_info->ppEnabledLayerNames, | |
| create_info->enabledLayerCount, | |
| create_info->ppEnabledExtensionNames, | |
| create_info->enabledExtensionCount); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| // use a local create info when the chain is not empty | |
| VkInstanceCreateInfo local_create_info; | |
| if (!chain.Empty()) { | |
| local_create_info = *create_info; | |
| chain.ModifyCreateInfo(local_create_info); | |
| create_info = &local_create_info; | |
| } | |
| return chain.Create(create_info, allocator, instance_out); | |
| } | |
| VkResult LayerChain::CreateDevice(VkPhysicalDevice physical_dev, | |
| const VkDeviceCreateInfo* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkDevice* dev_out) { | |
| const driver::DebugReportLogger logger = driver::Logger(physical_dev); | |
| LayerChain chain( | |
| false, logger, | |
| (allocator) ? *allocator : driver::GetData(physical_dev).allocator); | |
| VkResult result = chain.ActivateLayers( | |
| physical_dev, create_info->ppEnabledLayerNames, | |
| create_info->enabledLayerCount, create_info->ppEnabledExtensionNames, | |
| create_info->enabledExtensionCount); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| // use a local create info when the chain is not empty | |
| VkDeviceCreateInfo local_create_info; | |
| if (!chain.Empty()) { | |
| local_create_info = *create_info; | |
| chain.ModifyCreateInfo(local_create_info); | |
| create_info = &local_create_info; | |
| } | |
| return chain.Create(physical_dev, create_info, allocator, dev_out); | |
| } | |
| void LayerChain::DestroyInstance(VkInstance instance, | |
| const VkAllocationCallbacks* allocator) { | |
| InstanceData& data = GetData(instance); | |
| if (data.debug_callback != VK_NULL_HANDLE) | |
| data.destroy_debug_callback(instance, data.debug_callback, allocator); | |
| ActiveLayer* layers = reinterpret_cast<ActiveLayer*>(data.layers); | |
| uint32_t layer_count = data.layer_count; | |
| VkAllocationCallbacks local_allocator; | |
| if (!allocator) | |
| local_allocator = driver::GetData(instance).allocator; | |
| // this also destroys InstanceData | |
| data.dispatch.DestroyInstance(instance, allocator); | |
| DestroyLayers(layers, layer_count, | |
| (allocator) ? *allocator : local_allocator); | |
| } | |
| void LayerChain::DestroyDevice(VkDevice device, | |
| const VkAllocationCallbacks* allocator) { | |
| DeviceData& data = GetData(device); | |
| // this also destroys DeviceData | |
| data.dispatch.DestroyDevice(device, allocator); | |
| } | |
| const LayerChain::ActiveLayer* LayerChain::GetActiveLayers( | |
| VkPhysicalDevice physical_dev, | |
| uint32_t& count) { | |
| count = GetData(physical_dev).layer_count; | |
| return reinterpret_cast<const ActiveLayer*>(GetData(physical_dev).layers); | |
| } | |
| // ---------------------------------------------------------------------------- | |
| bool EnsureInitialized() { | |
| static std::once_flag once_flag; | |
| static bool initialized; | |
| std::call_once(once_flag, []() { | |
| if (driver::OpenHAL()) { | |
| DiscoverLayers(); | |
| initialized = true; | |
| } | |
| }); | |
| return initialized; | |
| } | |
| } // anonymous namespace | |
| VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, | |
| const VkAllocationCallbacks* pAllocator, | |
| VkInstance* pInstance) { | |
| if (!EnsureInitialized()) | |
| return VK_ERROR_INITIALIZATION_FAILED; | |
| return LayerChain::CreateInstance(pCreateInfo, pAllocator, pInstance); | |
| } | |
| void DestroyInstance(VkInstance instance, | |
| const VkAllocationCallbacks* pAllocator) { | |
| if (instance != VK_NULL_HANDLE) | |
| LayerChain::DestroyInstance(instance, pAllocator); | |
| } | |
| VkResult CreateDevice(VkPhysicalDevice physicalDevice, | |
| const VkDeviceCreateInfo* pCreateInfo, | |
| const VkAllocationCallbacks* pAllocator, | |
| VkDevice* pDevice) { | |
| return LayerChain::CreateDevice(physicalDevice, pCreateInfo, pAllocator, | |
| pDevice); | |
| } | |
| void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) { | |
| if (device != VK_NULL_HANDLE) | |
| LayerChain::DestroyDevice(device, pAllocator); | |
| } | |
| VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, | |
| VkLayerProperties* pProperties) { | |
| if (!EnsureInitialized()) | |
| return VK_ERROR_INITIALIZATION_FAILED; | |
| uint32_t count = GetLayerCount(); | |
| if (!pProperties) { | |
| *pPropertyCount = count; | |
| return VK_SUCCESS; | |
| } | |
| uint32_t copied = std::min(*pPropertyCount, count); | |
| for (uint32_t i = 0; i < copied; i++) | |
| pProperties[i] = GetLayerProperties(GetLayer(i)); | |
| *pPropertyCount = copied; | |
| return (copied == count) ? VK_SUCCESS : VK_INCOMPLETE; | |
| } | |
| VkResult EnumerateInstanceExtensionProperties( | |
| const char* pLayerName, | |
| uint32_t* pPropertyCount, | |
| VkExtensionProperties* pProperties) { | |
| if (!EnsureInitialized()) | |
| return VK_ERROR_INITIALIZATION_FAILED; | |
| if (pLayerName) { | |
| const Layer* layer = FindLayer(pLayerName); | |
| if (!layer) | |
| return VK_ERROR_LAYER_NOT_PRESENT; | |
| uint32_t count; | |
| const VkExtensionProperties* props = | |
| GetLayerInstanceExtensions(*layer, count); | |
| if (!pProperties || *pPropertyCount > count) | |
| *pPropertyCount = count; | |
| if (pProperties) | |
| std::copy(props, props + *pPropertyCount, pProperties); | |
| return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; | |
| } | |
| // TODO how about extensions from implicitly enabled layers? | |
| return vulkan::driver::EnumerateInstanceExtensionProperties( | |
| nullptr, pPropertyCount, pProperties); | |
| } | |
| VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, | |
| uint32_t* pPropertyCount, | |
| VkLayerProperties* pProperties) { | |
| uint32_t count; | |
| const LayerChain::ActiveLayer* layers = | |
| LayerChain::GetActiveLayers(physicalDevice, count); | |
| if (!pProperties) { | |
| *pPropertyCount = count; | |
| return VK_SUCCESS; | |
| } | |
| uint32_t copied = std::min(*pPropertyCount, count); | |
| for (uint32_t i = 0; i < copied; i++) | |
| pProperties[i] = GetLayerProperties(*layers[i].ref); | |
| *pPropertyCount = copied; | |
| return (copied == count) ? VK_SUCCESS : VK_INCOMPLETE; | |
| } | |
| VkResult EnumerateDeviceExtensionProperties( | |
| VkPhysicalDevice physicalDevice, | |
| const char* pLayerName, | |
| uint32_t* pPropertyCount, | |
| VkExtensionProperties* pProperties) { | |
| if (pLayerName) { | |
| // EnumerateDeviceLayerProperties enumerates active layers for | |
| // backward compatibility. The extension query here should work for | |
| // all layers. | |
| const Layer* layer = FindLayer(pLayerName); | |
| if (!layer) | |
| return VK_ERROR_LAYER_NOT_PRESENT; | |
| uint32_t count; | |
| const VkExtensionProperties* props = | |
| GetLayerDeviceExtensions(*layer, count); | |
| if (!pProperties || *pPropertyCount > count) | |
| *pPropertyCount = count; | |
| if (pProperties) | |
| std::copy(props, props + *pPropertyCount, pProperties); | |
| return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; | |
| } | |
| // TODO how about extensions from implicitly enabled layers? | |
| const InstanceData& data = GetData(physicalDevice); | |
| return data.dispatch.EnumerateDeviceExtensionProperties( | |
| physicalDevice, nullptr, pPropertyCount, pProperties); | |
| } | |
| } // namespace api | |
| } // namespace vulkan |