| /* |
| * 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. |
| |
| #define ATRACE_TAG ATRACE_TAG_GRAPHICS |
| |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <algorithm> |
| #include <mutex> |
| #include <new> |
| #include <string> |
| #include <unordered_set> |
| #include <utility> |
| |
| #include <android-base/properties.h> |
| #include <android-base/strings.h> |
| #include <cutils/properties.h> |
| #include <log/log.h> |
| #include <utils/Trace.h> |
| |
| #include <vulkan/vk_layer_interface.h> |
| #include <graphicsenv/GraphicsEnv.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_) |
| return; |
| |
| GetLayersFromSettings(); |
| |
| // If no layers specified via Settings, check legacy properties |
| if (implicit_layers_.count <= 0) { |
| ParseDebugVulkanLayers(); |
| ParseDebugVulkanLayer(); |
| |
| // 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 GetLayersFromSettings() { |
| // These will only be available if conditions are met in GraphicsEnvironment |
| // gpu_debug_layers = layer1:layer2:layerN |
| const std::string layers = android::GraphicsEnv::getInstance().getDebugLayers(); |
| if (!layers.empty()) { |
| ALOGV("Debug layer list: %s", layers.c_str()); |
| std::vector<std::string> paths = android::base::Split(layers, ":"); |
| for (uint32_t i = 0; i < paths.size(); i++) { |
| AddImplicitLayer(int(i), paths[i].c_str(), paths[i].length()); |
| } |
| } |
| } |
| |
| 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)); |
| } |
| |
| void ParseDebugVulkanLayer() { |
| // Checks for consecutive debug.vulkan.layer.<priority> system |
| // properties after always checking an initial fixed range. |
| static const char prefix[] = "debug.vulkan.layer."; |
| static constexpr int kFixedRangeBeginInclusive = 0; |
| static constexpr int kFixedRangeEndInclusive = 9; |
| |
| bool logged = false; |
| |
| int priority = kFixedRangeBeginInclusive; |
| while (true) { |
| const std::string prop_key = |
| std::string(prefix) + std::to_string(priority); |
| const std::string prop_val = |
| android::base::GetProperty(prop_key, ""); |
| |
| if (!prop_val.empty()) { |
| if (!logged) { |
| ALOGI( |
| "Detected Vulkan layers configured with " |
| "debug.vulkan.layer.<priority>. Checking for " |
| "debug.vulkan.layer.<priority> in the range [%d, %d] " |
| "followed by a consecutive scan.", |
| kFixedRangeBeginInclusive, kFixedRangeEndInclusive); |
| logged = true; |
| } |
| AddImplicitLayer(priority, prop_val.c_str(), prop_val.length()); |
| } else if (priority >= kFixedRangeEndInclusive) { |
| return; |
| } |
| |
| ++priority; |
| } |
| } |
| |
| 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_ && |
| android::GraphicsEnv::getInstance().isDebuggable() && |
| 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) { |
| // advertise the loader supported core Vulkan API version at vulkan::api |
| for (uint32_t i = driver::ProcHook::EXTENSION_CORE_1_0; |
| i != driver::ProcHook::EXTENSION_COUNT; ++i) { |
| enabled_extensions_.set(i); |
| } |
| } |
| |
| 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; |
| } |
| |
| if (!layer.ref.GetGetInstanceProcAddr()) { |
| ALOGW("Failed to locate vkGetInstanceProcAddr in 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) { |
| // Work-around a race condition during Android start-up, that can result |
| // in the second call to EnumerateDeviceExtensionProperties having |
| // another extension. That causes the second call to return |
| // VK_INCOMPLETE. A work-around is to add 1 to "count" and ask for one |
| // more extension property. See: http://anglebug.com/6715 and |
| // internal-to-Google b/206733351. |
| 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 bool initialized = false; |
| static pid_t init_attempted_for_pid = 0; |
| static std::mutex init_lock; |
| |
| std::lock_guard<std::mutex> lock(init_lock); |
| if (init_attempted_for_pid == getpid()) |
| return initialized; |
| |
| init_attempted_for_pid = getpid(); |
| if (driver::OpenHAL()) { |
| DiscoverLayers(); |
| initialized = true; |
| } |
| |
| return initialized; |
| } |
| |
| template <typename Functor> |
| void ForEachLayerFromSettings(Functor functor) { |
| const std::string layersSetting = |
| android::GraphicsEnv::getInstance().getDebugLayers(); |
| if (!layersSetting.empty()) { |
| std::vector<std::string> layers = |
| android::base::Split(layersSetting, ":"); |
| for (uint32_t i = 0; i < layers.size(); i++) { |
| const Layer* layer = FindLayer(layers[i].c_str()); |
| if (!layer) { |
| continue; |
| } |
| functor(layer); |
| } |
| } |
| } |
| |
| } // anonymous namespace |
| |
| VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, |
| VkInstance* pInstance) { |
| ATRACE_CALL(); |
| |
| if (!EnsureInitialized()) |
| return VK_ERROR_INITIALIZATION_FAILED; |
| |
| return LayerChain::CreateInstance(pCreateInfo, pAllocator, pInstance); |
| } |
| |
| void DestroyInstance(VkInstance instance, |
| const VkAllocationCallbacks* pAllocator) { |
| ATRACE_CALL(); |
| |
| if (instance != VK_NULL_HANDLE) |
| LayerChain::DestroyInstance(instance, pAllocator); |
| } |
| |
| VkResult CreateDevice(VkPhysicalDevice physicalDevice, |
| const VkDeviceCreateInfo* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, |
| VkDevice* pDevice) { |
| ATRACE_CALL(); |
| |
| return LayerChain::CreateDevice(physicalDevice, pCreateInfo, pAllocator, |
| pDevice); |
| } |
| |
| void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) { |
| ATRACE_CALL(); |
| |
| if (device != VK_NULL_HANDLE) |
| LayerChain::DestroyDevice(device, pAllocator); |
| } |
| |
| VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, |
| VkLayerProperties* pProperties) { |
| ATRACE_CALL(); |
| |
| if (!EnsureInitialized()) |
| return VK_ERROR_OUT_OF_HOST_MEMORY; |
| |
| 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) { |
| ATRACE_CALL(); |
| |
| if (!EnsureInitialized()) |
| return VK_ERROR_OUT_OF_HOST_MEMORY; |
| |
| 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; |
| } |
| |
| // If the pLayerName is nullptr, we must advertise all instance extensions |
| // from all implicitly enabled layers and the driver implementation. If |
| // there are duplicates among layers and the driver implementation, always |
| // only preserve the top layer closest to the application regardless of the |
| // spec version. |
| std::vector<VkExtensionProperties> properties; |
| std::unordered_set<std::string> extensionNames; |
| |
| // Expose extensions from implicitly enabled layers. |
| ForEachLayerFromSettings([&](const Layer* layer) { |
| uint32_t count = 0; |
| const VkExtensionProperties* props = |
| GetLayerInstanceExtensions(*layer, count); |
| if (count > 0) { |
| for (uint32_t i = 0; i < count; ++i) { |
| if (extensionNames.emplace(props[i].extensionName).second) { |
| properties.push_back(props[i]); |
| } |
| } |
| } |
| }); |
| |
| // TODO(b/143293104): Parse debug.vulkan.layers properties |
| |
| // Expose extensions from driver implementation. |
| { |
| uint32_t count = 0; |
| VkResult result = vulkan::driver::EnumerateInstanceExtensionProperties( |
| nullptr, &count, nullptr); |
| if (result == VK_SUCCESS && count > 0) { |
| std::vector<VkExtensionProperties> props(count); |
| result = vulkan::driver::EnumerateInstanceExtensionProperties( |
| nullptr, &count, props.data()); |
| for (auto prop : props) { |
| if (extensionNames.emplace(prop.extensionName).second) { |
| properties.push_back(prop); |
| } |
| } |
| } |
| } |
| |
| uint32_t totalCount = properties.size(); |
| if (!pProperties || *pPropertyCount > totalCount) { |
| *pPropertyCount = totalCount; |
| } |
| if (pProperties) { |
| std::copy(properties.data(), properties.data() + *pPropertyCount, |
| pProperties); |
| } |
| return *pPropertyCount < totalCount ? VK_INCOMPLETE : VK_SUCCESS; |
| } |
| |
| VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, |
| uint32_t* pPropertyCount, |
| VkLayerProperties* pProperties) { |
| ATRACE_CALL(); |
| |
| 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) { |
| ATRACE_CALL(); |
| |
| 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; |
| } |
| |
| // If the pLayerName is nullptr, we must advertise all device extensions |
| // from all implicitly enabled layers and the driver implementation. If |
| // there are duplicates among layers and the driver implementation, always |
| // only preserve the top layer closest to the application regardless of the |
| // spec version. |
| std::vector<VkExtensionProperties> properties; |
| std::unordered_set<std::string> extensionNames; |
| |
| // Expose extensions from implicitly enabled layers. |
| ForEachLayerFromSettings([&](const Layer* layer) { |
| uint32_t count = 0; |
| const VkExtensionProperties* props = |
| GetLayerDeviceExtensions(*layer, count); |
| if (count > 0) { |
| for (uint32_t i = 0; i < count; ++i) { |
| if (extensionNames.emplace(props[i].extensionName).second) { |
| properties.push_back(props[i]); |
| } |
| } |
| } |
| }); |
| |
| // TODO(b/143293104): Parse debug.vulkan.layers properties |
| |
| // Expose extensions from driver implementation. |
| { |
| const InstanceData& data = GetData(physicalDevice); |
| uint32_t count = 0; |
| VkResult result = data.dispatch.EnumerateDeviceExtensionProperties( |
| physicalDevice, nullptr, &count, nullptr); |
| if (result == VK_SUCCESS && count > 0) { |
| std::vector<VkExtensionProperties> props(count); |
| result = data.dispatch.EnumerateDeviceExtensionProperties( |
| physicalDevice, nullptr, &count, props.data()); |
| for (auto prop : props) { |
| if (extensionNames.emplace(prop.extensionName).second) { |
| properties.push_back(prop); |
| } |
| } |
| } |
| } |
| |
| uint32_t totalCount = properties.size(); |
| if (!pProperties || *pPropertyCount > totalCount) { |
| *pPropertyCount = totalCount; |
| } |
| if (pProperties) { |
| std::copy(properties.data(), properties.data() + *pPropertyCount, |
| pProperties); |
| } |
| return *pPropertyCount < totalCount ? VK_INCOMPLETE : VK_SUCCESS; |
| } |
| |
| VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) { |
| ATRACE_CALL(); |
| |
| // Load the driver here if not done yet. This api will be used in Zygote |
| // for Vulkan driver pre-loading because of the minimum overhead. |
| if (!EnsureInitialized()) |
| return VK_ERROR_OUT_OF_HOST_MEMORY; |
| |
| *pApiVersion = VK_API_VERSION_1_2; |
| return VK_SUCCESS; |
| } |
| |
| } // namespace api |
| } // namespace vulkan |