| /* |
| * 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 "loader.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) { |
| add_implicit_layers(); |
| |
| 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_ = allocate_name_array(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] = get_implicit_layer_name(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 (is_implicit_layer(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 add_implicit_layers() { |
| if (!driver::Debuggable()) |
| return; |
| |
| parse_debug_vulkan_layers(); |
| property_list(parse_debug_vulkan_layer, 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 parse_debug_vulkan_layers() { |
| // 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) |
| add_implicit_layer(prio, p, static_cast<size_t>(delim - p)); |
| |
| prio++; |
| p = delim + 1; |
| } |
| |
| if (p[0] != '\0') |
| add_implicit_layer(prio, p, strlen(p)); |
| } |
| |
| static void parse_debug_vulkan_layer(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.add_implicit_layer(priority, val, strlen(val)); |
| } |
| |
| void add_implicit_layer(int priority, const char* name, size_t len) { |
| if (!grow_implicit_layer_array(1, 0)) |
| return; |
| |
| auto& arr = implicit_layers_; |
| auto& layer = arr.elements[arr.count++]; |
| |
| layer.priority = priority; |
| layer.name_offset = add_implicit_layer_name(name, len); |
| |
| ALOGV("Added implicit layer %s", |
| get_implicit_layer_name(arr.count - 1)); |
| } |
| |
| size_t add_implicit_layer_name(const char* name, size_t len) { |
| if (!grow_implicit_layer_array(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 grow_implicit_layer_array(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* get_implicit_layer_name(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 is_implicit_layer(const char* name) const { |
| const auto& arr = implicit_layers_; |
| |
| for (uint32_t i = 0; i < arr.count; i++) { |
| if (strcmp(name, get_implicit_layer_name(i)) == 0) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| const char** allocate_name_array(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 (!enable_debug_callback()) |
| return VK_SUCCESS; |
| |
| names_ = allocate_name_array(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 install_debug_callback() const { return install_debug_callback_; } |
| |
| private: |
| bool enable_debug_callback() const { |
| return (is_instance_ && driver::Debuggable() && |
| property_get_bool("debug.vulkan.enable_callback", false)); |
| } |
| |
| const char** allocate_name_array(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: |
| static VkResult create_instance(const VkInstanceCreateInfo* create_info, |
| const VkAllocationCallbacks* allocator, |
| VkInstance* instance_out); |
| |
| static VkResult create_device(VkPhysicalDevice physical_dev, |
| const VkDeviceCreateInfo* create_info, |
| const VkAllocationCallbacks* allocator, |
| VkDevice* dev_out); |
| |
| static void destroy_instance(VkInstance instance, |
| const VkAllocationCallbacks* allocator); |
| |
| static void destroy_device(VkDevice dev, |
| const VkAllocationCallbacks* allocator); |
| |
| private: |
| struct ActiveLayer { |
| LayerRef ref; |
| union { |
| VkLayerInstanceLink instance_link; |
| VkLayerDeviceLink device_link; |
| }; |
| }; |
| |
| LayerChain(bool is_instance, const VkAllocationCallbacks& allocator); |
| ~LayerChain(); |
| |
| VkResult activate_layers(const char* const* layer_names, |
| uint32_t layer_count, |
| const char* const* extension_names, |
| uint32_t extension_count); |
| ActiveLayer* allocate_layer_array(uint32_t count) const; |
| VkResult load_layer(ActiveLayer& layer, const char* name); |
| void setup_layer_links(); |
| |
| bool empty() const; |
| void modify_create_info(VkInstanceCreateInfo& info); |
| void modify_create_info(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); |
| |
| template <typename DataType> |
| void steal_layers(DataType& data); |
| |
| static void destroy_layers(ActiveLayer* layers, |
| uint32_t count, |
| const VkAllocationCallbacks& allocator); |
| |
| static VKAPI_ATTR VkBool32 |
| debug_report_callback(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 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_; |
| VkLayerDeviceCreateInfo device_chain_info_; |
| }; |
| }; |
| |
| LayerChain::LayerChain(bool is_instance, const VkAllocationCallbacks& allocator) |
| : is_instance_(is_instance), |
| 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) {} |
| |
| LayerChain::~LayerChain() { |
| destroy_layers(layers_, layer_count_, allocator_); |
| } |
| |
| VkResult LayerChain::activate_layers(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; |
| if (!is_instance_) |
| get_device_proc_addr_ = driver::GetDeviceProcAddr; |
| |
| return VK_SUCCESS; |
| } |
| |
| layers_ = allocate_layer_array(layer_count); |
| if (!layers_) |
| return VK_ERROR_OUT_OF_HOST_MEMORY; |
| |
| // load layers |
| for (uint32_t i = 0; i < layer_count; i++) { |
| result = load_layer(layers_[i], layer_names[i]); |
| if (result != VK_SUCCESS) |
| return result; |
| |
| // count loaded layers for proper destructions on errors |
| layer_count_++; |
| } |
| |
| setup_layer_links(); |
| |
| return VK_SUCCESS; |
| } |
| |
| LayerChain::ActiveLayer* LayerChain::allocate_layer_array( |
| uint32_t count) const { |
| VkSystemAllocationScope scope = (is_instance_) |
| ? VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE |
| : VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; |
| |
| return reinterpret_cast<ActiveLayer*>(allocator_.pfnAllocation( |
| allocator_.pUserData, sizeof(ActiveLayer) * count, alignof(ActiveLayer), |
| scope)); |
| } |
| |
| VkResult LayerChain::load_layer(ActiveLayer& layer, const char* name) { |
| if (is_instance_) |
| new (&layer) ActiveLayer{GetInstanceLayerRef(name), {}}; |
| else |
| new (&layer) ActiveLayer{GetDeviceLayerRef(name), {}}; |
| |
| if (!layer.ref) { |
| ALOGE("Failed to load layer %s", name); |
| layer.ref.~LayerRef(); |
| return VK_ERROR_LAYER_NOT_PRESENT; |
| } |
| |
| ALOGI("Loaded %s layer %s", (is_instance_) ? "instance" : "device", name); |
| |
| return VK_SUCCESS; |
| } |
| |
| void LayerChain::setup_layer_links() { |
| 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::modify_create_info(VkInstanceCreateInfo& info) { |
| if (layer_count_) { |
| const ActiveLayer& layer = layers_[0]; |
| |
| instance_chain_info_.sType = |
| VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; |
| instance_chain_info_.function = VK_LAYER_FUNCTION_LINK; |
| // TODO fix vk_layer_interface.h and get rid of const_cast? |
| instance_chain_info_.u.pLayerInfo = |
| const_cast<VkLayerInstanceLink*>(&layer.instance_link); |
| |
| // insert layer info |
| instance_chain_info_.pNext = info.pNext; |
| info.pNext = &instance_chain_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::modify_create_info(VkDeviceCreateInfo& info) { |
| if (layer_count_) { |
| const ActiveLayer& layer = layers_[0]; |
| |
| device_chain_info_.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; |
| device_chain_info_.function = VK_LAYER_FUNCTION_LINK; |
| // TODO fix vk_layer_interface.h and get rid of const_cast? |
| device_chain_info_.u.pLayerInfo = |
| const_cast<VkLayerDeviceLink*>(&layer.device_link); |
| |
| // insert layer info |
| device_chain_info_.pNext = info.pNext; |
| info.pNext = &device_chain_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) { |
| // call down the chain |
| PFN_vkCreateInstance create_instance = |
| reinterpret_cast<PFN_vkCreateInstance>( |
| get_instance_proc_addr_(VK_NULL_HANDLE, "vkCreateInstance")); |
| VkInstance instance; |
| VkResult result = create_instance(create_info, allocator, &instance); |
| if (result != VK_SUCCESS) |
| return result; |
| |
| // initialize InstanceData |
| InstanceData& data = GetData(instance); |
| memset(&data, 0, sizeof(data)); |
| |
| data.instance = instance; |
| |
| if (!InitDispatchTable(instance, get_instance_proc_addr_)) { |
| if (data.dispatch.DestroyInstance) |
| data.dispatch.DestroyInstance(instance, allocator); |
| |
| return VK_ERROR_INITIALIZATION_FAILED; |
| } |
| |
| // install debug report callback |
| if (override_extensions_.install_debug_callback()) { |
| 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 = debug_report_callback; |
| |
| 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"); |
| } |
| |
| steal_layers(data); |
| |
| *instance_out = instance; |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult LayerChain::create(VkPhysicalDevice physical_dev, |
| const VkDeviceCreateInfo* create_info, |
| const VkAllocationCallbacks* allocator, |
| VkDevice* dev_out) { |
| // call down the chain |
| // |
| // TODO Instance call chain available at |
| // GetData(physical_dev).dispatch.CreateDevice is ignored. Is that |
| // right? |
| VkInstance instance = GetData(physical_dev).instance; |
| PFN_vkCreateDevice create_device = reinterpret_cast<PFN_vkCreateDevice>( |
| get_instance_proc_addr_(instance, "vkCreateDevice")); |
| VkDevice dev; |
| VkResult result = create_device(physical_dev, create_info, allocator, &dev); |
| if (result != VK_SUCCESS) |
| return result; |
| |
| // initialize DeviceData |
| DeviceData& data = GetData(dev); |
| memset(&data, 0, sizeof(data)); |
| |
| if (!InitDispatchTable(dev, get_device_proc_addr_)) { |
| if (data.dispatch.DestroyDevice) |
| data.dispatch.DestroyDevice(dev, allocator); |
| |
| return VK_ERROR_INITIALIZATION_FAILED; |
| } |
| |
| steal_layers(data); |
| |
| *dev_out = dev; |
| |
| return VK_SUCCESS; |
| } |
| |
| template <typename DataType> |
| void LayerChain::steal_layers(DataType& data) { |
| data.layers = layers_; |
| data.layer_count = layer_count_; |
| |
| layers_ = nullptr; |
| layer_count_ = 0; |
| } |
| |
| void LayerChain::destroy_layers(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); |
| } |
| |
| VkBool32 LayerChain::debug_report_callback(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::create_instance(const VkInstanceCreateInfo* create_info, |
| const VkAllocationCallbacks* allocator, |
| VkInstance* instance_out) { |
| LayerChain chain(true, |
| (allocator) ? *allocator : driver::GetDefaultAllocator()); |
| |
| VkResult result = chain.activate_layers( |
| 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.modify_create_info(local_create_info); |
| create_info = &local_create_info; |
| } |
| |
| return chain.create(create_info, allocator, instance_out); |
| } |
| |
| VkResult LayerChain::create_device(VkPhysicalDevice physical_dev, |
| const VkDeviceCreateInfo* create_info, |
| const VkAllocationCallbacks* allocator, |
| VkDevice* dev_out) { |
| LayerChain chain(false, (allocator) |
| ? *allocator |
| : driver::GetData(physical_dev).allocator); |
| |
| VkResult result = chain.activate_layers( |
| 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.modify_create_info(local_create_info); |
| create_info = &local_create_info; |
| } |
| |
| return chain.create(physical_dev, create_info, allocator, dev_out); |
| } |
| |
| void LayerChain::destroy_instance(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); |
| |
| destroy_layers(layers, layer_count, |
| (allocator) ? *allocator : local_allocator); |
| } |
| |
| void LayerChain::destroy_device(VkDevice device, |
| const VkAllocationCallbacks* allocator) { |
| DeviceData& data = GetData(device); |
| |
| ActiveLayer* layers = reinterpret_cast<ActiveLayer*>(data.layers); |
| uint32_t layer_count = data.layer_count; |
| |
| VkAllocationCallbacks local_allocator; |
| if (!allocator) |
| local_allocator = driver::GetData(device).allocator; |
| |
| // this also destroys DeviceData |
| data.dispatch.DestroyDevice(device, allocator); |
| |
| destroy_layers(layers, layer_count, |
| (allocator) ? *allocator : local_allocator); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| 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::create_instance(pCreateInfo, pAllocator, pInstance); |
| } |
| |
| void DestroyInstance(VkInstance instance, |
| const VkAllocationCallbacks* pAllocator) { |
| if (instance != VK_NULL_HANDLE) |
| LayerChain::destroy_instance(instance, pAllocator); |
| } |
| |
| VkResult CreateDevice(VkPhysicalDevice physicalDevice, |
| const VkDeviceCreateInfo* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, |
| VkDevice* pDevice) { |
| return LayerChain::create_device(physicalDevice, pCreateInfo, pAllocator, |
| pDevice); |
| } |
| |
| void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) { |
| if (device != VK_NULL_HANDLE) |
| LayerChain::destroy_device(device, pAllocator); |
| } |
| |
| VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, |
| VkLayerProperties* pProperties) { |
| if (!EnsureInitialized()) |
| return VK_ERROR_INITIALIZATION_FAILED; |
| |
| uint32_t count = |
| EnumerateInstanceLayers(pProperties ? *pPropertyCount : 0, pProperties); |
| |
| if (!pProperties || *pPropertyCount > count) |
| *pPropertyCount = count; |
| |
| return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; |
| } |
| |
| VkResult EnumerateInstanceExtensionProperties( |
| const char* pLayerName, |
| uint32_t* pPropertyCount, |
| VkExtensionProperties* pProperties) { |
| if (!EnsureInitialized()) |
| return VK_ERROR_INITIALIZATION_FAILED; |
| |
| if (pLayerName) { |
| const VkExtensionProperties* props; |
| uint32_t count; |
| GetInstanceLayerExtensions(pLayerName, &props, &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) { |
| (void)physicalDevice; |
| |
| uint32_t count = |
| EnumerateDeviceLayers(pProperties ? *pPropertyCount : 0, pProperties); |
| |
| if (!pProperties || *pPropertyCount > count) |
| *pPropertyCount = count; |
| |
| return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; |
| } |
| |
| VkResult EnumerateDeviceExtensionProperties( |
| VkPhysicalDevice physicalDevice, |
| const char* pLayerName, |
| uint32_t* pPropertyCount, |
| VkExtensionProperties* pProperties) { |
| if (pLayerName) { |
| const VkExtensionProperties* props; |
| uint32_t count; |
| GetDeviceLayerExtensions(pLayerName, &props, &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 |