vulkan: check for unsupported extensions
Return VK_ERROR_EXTENSION_NOT_PRESENT when an app attempts to enable an
unsupported extension. This fixes a regression introduced by my top
rewrite (commit 0c20324: vulkan: rewrite top of loader).
Since we do not cache HAL extensions, each vkCreateInstance or
vkCreateDevice call is preceded by two extension enumeration calls
internally.
Change-Id: I5342c1a5c9a5452dd2bc52933a5ee558db174048
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 9c5aa3b..549886f 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -416,6 +416,16 @@
const VkAllocationCallbacks* allocator,
VkDevice* dev_out);
+ VkResult validate_extensions(const char* const* extension_names,
+ uint32_t extension_count);
+ VkResult validate_extensions(VkPhysicalDevice physical_dev,
+ const char* const* extension_names,
+ uint32_t extension_count);
+ VkExtensionProperties* allocate_driver_extension_array(
+ uint32_t count) const;
+ bool is_layer_extension(const char* name) const;
+ bool is_driver_extension(const char* name) const;
+
template <typename DataType>
void steal_layers(DataType& data);
@@ -449,6 +459,9 @@
VkLayerInstanceCreateInfo instance_chain_info_;
VkLayerDeviceCreateInfo device_chain_info_;
};
+
+ VkExtensionProperties* driver_extensions_;
+ uint32_t driver_extension_count_;
};
LayerChain::LayerChain(bool is_instance, const VkAllocationCallbacks& allocator)
@@ -459,9 +472,12 @@
layers_(nullptr),
layer_count_(0),
get_instance_proc_addr_(nullptr),
- get_device_proc_addr_(nullptr) {}
+ get_device_proc_addr_(nullptr),
+ driver_extensions_(nullptr),
+ driver_extension_count_(0) {}
LayerChain::~LayerChain() {
+ allocator_.pfnFree(allocator_.pUserData, driver_extensions_);
destroy_layers(layers_, layer_count_, allocator_);
}
@@ -657,12 +673,17 @@
VkResult LayerChain::create(const VkInstanceCreateInfo* create_info,
const VkAllocationCallbacks* allocator,
VkInstance* instance_out) {
+ VkResult result = validate_extensions(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;
- VkResult result = create_instance(create_info, allocator, &instance);
+ result = create_instance(create_info, allocator, &instance);
if (result != VK_SUCCESS)
return result;
@@ -727,6 +748,12 @@
const VkDeviceCreateInfo* create_info,
const VkAllocationCallbacks* allocator,
VkDevice* dev_out) {
+ VkResult result =
+ validate_extensions(physical_dev, create_info->ppEnabledExtensionNames,
+ create_info->enabledExtensionCount);
+ if (result != VK_SUCCESS)
+ return result;
+
// call down the chain
//
// TODO Instance call chain available at
@@ -736,7 +763,7 @@
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);
+ result = create_device(physical_dev, create_info, allocator, &dev);
if (result != VK_SUCCESS)
return result;
@@ -758,6 +785,96 @@
return VK_SUCCESS;
}
+VkResult LayerChain::validate_extensions(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_ = allocate_driver_extension_array(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 (!is_layer_extension(name) && !is_driver_extension(name)) {
+ ALOGE("Failed to enable missing instance extension %s", name);
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult LayerChain::validate_extensions(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_ = allocate_driver_extension_array(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 (!is_layer_extension(name) && !is_driver_extension(name)) {
+ ALOGE("Failed to enable missing device extension %s", name);
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
+VkExtensionProperties* LayerChain::allocate_driver_extension_array(
+ uint32_t count) const {
+ return reinterpret_cast<VkExtensionProperties*>(allocator_.pfnAllocation(
+ allocator_.pUserData, sizeof(VkExtensionProperties) * count,
+ alignof(VkExtensionProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+}
+
+bool LayerChain::is_layer_extension(const char* name) const {
+ for (uint32_t i = 0; i < layer_count_; i++) {
+ const ActiveLayer& layer = layers_[i];
+ if (layer.ref.SupportsExtension(name))
+ return true;
+ }
+
+ return false;
+}
+
+bool LayerChain::is_driver_extension(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::steal_layers(DataType& data) {
data.layers = layers_;