vulkan: Driver device extension enumeration and filtering
- Return VK_ERROR_EXTENSION_NOT_PRESENT if a requested device
extension is not supported by the loader, driver, or any enabled
device layer.
- Filter out device extensions not supported by the driver when
creating the driver device.
- Enumerate device extensions supported by the driver or loader.
Change-Id: I538e37bc74cc7f0eb27b1211b9324fb3b8a06e14
(cherry picked from commit 35873021f4f79ded0f584e433076c2675c6aed69)
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index f2fbf31..3e7fbec 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -28,6 +28,12 @@
using namespace vulkan;
+// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
+// not a good long-term solution. Having a hard-coded enum of extensions is
+// bad, of course. Representing sets of extensions (requested, supported, etc.)
+// as a bitset isn't necessarily bad, if the mapping from extension to bit were
+// dynamic. Need to rethink this completely when there's a little more time.
+
// TODO(jessehall): This file currently builds up global data structures as it
// loads, and never cleans them up. This means we're doing heap allocations
// without going through an app-provided allocator, but worse, we'll leak those
@@ -184,7 +190,7 @@
}
g_instance_layers.push_back(layer);
- ALOGV("added instance layer '%s'", props.layerName);
+ ALOGV(" added instance layer '%s'", props.layerName);
}
for (size_t i = 0; i < num_device_layers; i++) {
const VkLayerProperties& props = properties[num_instance_layers + i];
@@ -226,7 +232,7 @@
}
g_device_layers.push_back(layer);
- ALOGV("added device layer '%s'", props.layerName);
+ ALOGV(" added device layer '%s'", props.layerName);
}
dlclose(dlhandle);
@@ -396,6 +402,13 @@
: nullptr;
}
+bool LayerRef::SupportsExtension(const char* name) const {
+ return std::find_if(layer_->extensions.cbegin(), layer_->extensions.cend(),
+ [=](const VkExtensionProperties& ext) {
+ return strcmp(ext.extensionName, name) == 0;
+ }) != layer_->extensions.cend();
+}
+
InstanceExtension InstanceExtensionFromName(const char* name) {
if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0)
return kKHR_surface;
@@ -406,4 +419,12 @@
return kInstanceExtensionCount;
}
+DeviceExtension DeviceExtensionFromName(const char* name) {
+ if (strcmp(name, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
+ return kKHR_swapchain;
+ if (strcmp(name, VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) == 0)
+ return kANDROID_native_buffer;
+ return kDeviceExtensionCount;
+}
+
} // namespace vulkan
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 985b7e4..5abd3c5 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -268,6 +268,7 @@
const VkAllocationCallbacks* alloc;
uint32_t num_physical_devices;
VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
+ DeviceExtensionSet physical_device_driver_extensions[kMaxPhysicalDevices];
Vector<LayerRef> active_layers;
VkDebugReportCallbackEXT message;
@@ -275,7 +276,6 @@
struct {
VkInstance instance;
- InstanceExtensionSet supported_extensions;
DriverDispatchTable dispatch;
uint32_t num_physical_devices;
} drv; // may eventually be an array
@@ -582,6 +582,9 @@
DestroyInstance_Bottom(instance.handle, allocator);
return VK_ERROR_INITIALIZATION_FAILED;
}
+
+ Vector<VkExtensionProperties> extensions(
+ Vector<VkExtensionProperties>::allocator_type(instance.alloc));
for (uint32_t i = 0; i < num_physical_devices; i++) {
hwvulkan_dispatch_t* pdev_dispatch =
reinterpret_cast<hwvulkan_dispatch_t*>(
@@ -593,10 +596,41 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
pdev_dispatch->vtbl = instance.dispatch_ptr;
+
+ uint32_t count;
+ if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties(
+ instance.physical_devices[i], nullptr, &count, nullptr)) !=
+ VK_SUCCESS) {
+ ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i,
+ result);
+ continue;
+ }
+ extensions.resize(count);
+ if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties(
+ instance.physical_devices[i], nullptr, &count,
+ extensions.data())) != VK_SUCCESS) {
+ ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i,
+ result);
+ continue;
+ }
+ ALOGV_IF(count > 0, "driver gpu[%u] supports extensions:", i);
+ for (const auto& extension : extensions) {
+ ALOGV(" %s (v%u)", extension.extensionName, extension.specVersion);
+ DeviceExtension id =
+ DeviceExtensionFromName(extension.extensionName);
+ if (id == kDeviceExtensionCount) {
+ ALOGW("driver gpu[%u] extension '%s' unknown to loader", i,
+ extension.extensionName);
+ } else {
+ instance.physical_device_driver_extensions[i].set(id);
+ }
+ }
+ // Ignore driver attempts to support loader extensions
+ instance.physical_device_driver_extensions[i].reset(kKHR_swapchain);
}
instance.drv.num_physical_devices = num_physical_devices;
-
instance.num_physical_devices = instance.drv.num_physical_devices;
+
return VK_SUCCESS;
}
@@ -686,7 +720,7 @@
VKAPI_ATTR
VkResult EnumerateDeviceExtensionProperties_Bottom(
- VkPhysicalDevice /*pdev*/,
+ VkPhysicalDevice gpu,
const char* layer_name,
uint32_t* properties_count,
VkExtensionProperties* properties) {
@@ -695,7 +729,26 @@
if (layer_name) {
GetDeviceLayerExtensions(layer_name, &extensions, &num_extensions);
} else {
- // TODO(jessehall)
+ Instance& instance = GetDispatchParent(gpu);
+ size_t gpu_idx = 0;
+ while (instance.physical_devices[gpu_idx] != gpu)
+ gpu_idx++;
+ const DeviceExtensionSet driver_extensions =
+ instance.physical_device_driver_extensions[gpu_idx];
+
+ // We only support VK_KHR_swapchain if the GPU supports
+ // VK_ANDROID_native_buffer
+ VkExtensionProperties* available = static_cast<VkExtensionProperties*>(
+ alloca(kDeviceExtensionCount * sizeof(VkExtensionProperties)));
+ if (driver_extensions[kANDROID_native_buffer]) {
+ available[num_extensions++] = VkExtensionProperties{
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_SPEC_VERSION};
+ }
+
+ // TODO(jessehall): We need to also enumerate extensions supported by
+ // implicitly-enabled layers. Currently we don't have that list of
+ // layers until instance creation.
+ extensions = available;
}
if (!properties || *properties_count > num_extensions)
@@ -717,11 +770,11 @@
}
VKAPI_ATTR
-VkResult CreateDevice_Bottom(VkPhysicalDevice pdev,
+VkResult CreateDevice_Bottom(VkPhysicalDevice gpu,
const VkDeviceCreateInfo* create_info,
const VkAllocationCallbacks* allocator,
VkDevice* device_out) {
- Instance& instance = GetDispatchParent(pdev);
+ Instance& instance = GetDispatchParent(gpu);
VkResult result;
if (!allocator) {
@@ -744,7 +797,41 @@
return result;
}
- const char* kAndroidNativeBufferExtensionName = "VK_ANDROID_native_buffer";
+ size_t gpu_idx = 0;
+ while (instance.physical_devices[gpu_idx] != gpu)
+ gpu_idx++;
+
+ uint32_t num_driver_extensions = 0;
+ const char** driver_extensions = static_cast<const char**>(
+ alloca(create_info->enabledExtensionCount * sizeof(const char*)));
+ for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
+ const char* name = create_info->ppEnabledExtensionNames[i];
+
+ DeviceExtension id = DeviceExtensionFromName(name);
+ if (id < kDeviceExtensionCount &&
+ (instance.physical_device_driver_extensions[gpu_idx][id] ||
+ id == kKHR_swapchain)) {
+ if (id == kKHR_swapchain)
+ name = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
+ driver_extensions[num_driver_extensions++] = name;
+ continue;
+ }
+
+ bool supported = false;
+ for (const auto& layer : device->active_layers) {
+ if (layer.SupportsExtension(name))
+ supported = true;
+ }
+ if (!supported) {
+ ALOGE(
+ "requested device extension '%s' not supported by driver or "
+ "any active layers",
+ name);
+ DestroyDevice(device);
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ }
+ }
+
VkDeviceCreateInfo driver_create_info = *create_info;
driver_create_info.enabledLayerCount = 0;
driver_create_info.ppEnabledLayerNames = nullptr;
@@ -753,12 +840,12 @@
// supported by the driver here. Also, add the VK_ANDROID_native_buffer
// extension to the list iff the VK_KHR_swapchain extension was requested,
// instead of adding it unconditionally like we do now.
- driver_create_info.enabledExtensionCount = 1;
- driver_create_info.ppEnabledExtensionNames = &kAndroidNativeBufferExtensionName;
+ driver_create_info.enabledExtensionCount = num_driver_extensions;
+ driver_create_info.ppEnabledExtensionNames = driver_extensions;
VkDevice drv_device;
- result = instance.drv.dispatch.CreateDevice(pdev, &driver_create_info, allocator,
- &drv_device);
+ result = instance.drv.dispatch.CreateDevice(gpu, &driver_create_info,
+ allocator, &drv_device);
if (result != VK_SUCCESS) {
DestroyDevice(device);
return result;
@@ -817,7 +904,7 @@
// therefore which functions to return procaddrs for.
PFN_vkCreateDevice create_device = reinterpret_cast<PFN_vkCreateDevice>(
next_get_proc_addr(drv_device, "vkCreateDevice"));
- create_device(pdev, create_info, allocator, &drv_device);
+ create_device(gpu, create_info, allocator, &drv_device);
if (!LoadDeviceDispatchTable(static_cast<VkDevice>(base_object),
next_get_proc_addr, device->dispatch)) {
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index 375396e..3e2d1c4 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -31,6 +31,13 @@
};
typedef std::bitset<kInstanceExtensionCount> InstanceExtensionSet;
+enum DeviceExtension {
+ kKHR_swapchain,
+ kANDROID_native_buffer,
+ kDeviceExtensionCount
+};
+typedef std::bitset<kDeviceExtensionCount> DeviceExtensionSet;
+
inline const InstanceDispatchTable& GetDispatchTable(VkInstance instance) {
return **reinterpret_cast<InstanceDispatchTable**>(instance);
}
@@ -149,6 +156,8 @@
PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;
PFN_vkGetDeviceProcAddr GetGetDeviceProcAddr() const;
+ bool SupportsExtension(const char* name) const;
+
private:
Layer* layer_;
};
@@ -166,6 +175,7 @@
LayerRef GetDeviceLayerRef(const char* name);
InstanceExtension InstanceExtensionFromName(const char* name);
+DeviceExtension DeviceExtensionFromName(const char* name);
} // namespace vulkan
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index c66ec95..e12409c 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -38,7 +38,6 @@
VkAllocationCallbacks allocator;
VkPhysicalDevice_T physical_device;
uint64_t next_callback_handle;
- bool debug_report_enabled;
};
struct VkQueue_T {
@@ -251,13 +250,15 @@
instance->allocator = *allocator;
instance->physical_device.dispatch.magic = HWVULKAN_DISPATCH_MAGIC;
instance->next_callback_handle = 0;
- instance->debug_report_enabled = false;
for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
if (strcmp(create_info->ppEnabledExtensionNames[i],
VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
- ALOGV("Enabling " VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
- instance->debug_report_enabled = true;
+ ALOGV("instance extension '%s' requested",
+ create_info->ppEnabledExtensionNames[i]);
+ } else {
+ ALOGW("unsupported extension '%s' requested",
+ create_info->ppEnabledExtensionNames[i]);
}
}
@@ -375,7 +376,7 @@
// Device
VkResult CreateDevice(VkPhysicalDevice physical_device,
- const VkDeviceCreateInfo*,
+ const VkDeviceCreateInfo* create_info,
const VkAllocationCallbacks* allocator,
VkDevice* out_device) {
VkInstance_T* instance = GetInstanceFromPhysicalDevice(physical_device);
@@ -394,6 +395,13 @@
std::fill(device->next_handle.begin(), device->next_handle.end(),
UINT64_C(0));
+ for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
+ if (strcmp(create_info->ppEnabledExtensionNames[i],
+ VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) == 0) {
+ ALOGV("Enabling " VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME);
+ }
+ }
+
*out_device = device;
return VK_SUCCESS;
}
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
index 71f989e..a2f4e8f 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -32,6 +32,7 @@
struct GpuInfo {
VkPhysicalDeviceProperties properties;
VkPhysicalDeviceMemoryProperties memory;
+ VkPhysicalDeviceFeatures features;
std::vector<VkQueueFamilyProperties> queue_families;
std::vector<VkExtensionProperties> extensions;
std::vector<VkLayerProperties> layers;
@@ -115,6 +116,70 @@
die("vkEnumerateDeviceExtensionProperties (data)", result);
}
+void GatherGpuInfo(VkPhysicalDevice gpu, GpuInfo& info) {
+ VkResult result;
+ uint32_t count;
+
+ vkGetPhysicalDeviceProperties(gpu, &info.properties);
+ vkGetPhysicalDeviceMemoryProperties(gpu, &info.memory);
+ vkGetPhysicalDeviceFeatures(gpu, &info.features);
+
+ vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
+ info.queue_families.resize(count);
+ vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count,
+ info.queue_families.data());
+
+ result = vkEnumerateDeviceLayerProperties(gpu, &count, nullptr);
+ if (result != VK_SUCCESS)
+ die("vkEnumerateDeviceLayerProperties (count)", result);
+ do {
+ info.layers.resize(count);
+ result =
+ vkEnumerateDeviceLayerProperties(gpu, &count, info.layers.data());
+ } while (result == VK_INCOMPLETE);
+ if (result != VK_SUCCESS)
+ die("vkEnumerateDeviceLayerProperties (data)", result);
+ info.layer_extensions.resize(info.layers.size());
+
+ EnumerateDeviceExtensions(gpu, nullptr, &info.extensions);
+ for (size_t i = 0; i < info.layers.size(); i++) {
+ EnumerateDeviceExtensions(gpu, info.layers[i].layerName,
+ &info.layer_extensions[i]);
+ }
+
+ const std::array<const char*, 1> kDesiredExtensions = {
+ {VK_KHR_SWAPCHAIN_EXTENSION_NAME},
+ };
+ const char* extensions[kDesiredExtensions.size()];
+ uint32_t num_extensions = 0;
+ for (const auto& desired_ext : kDesiredExtensions) {
+ bool available = HasExtension(info.extensions, desired_ext);
+ for (size_t i = 0; !available && i < info.layer_extensions.size(); i++)
+ available = HasExtension(info.layer_extensions[i], desired_ext);
+ if (available)
+ extensions[num_extensions++] = desired_ext;
+ }
+
+ VkDevice device;
+ const VkDeviceQueueCreateInfo queue_create_info = {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ .queueFamilyIndex = 0,
+ .queueCount = 1,
+ };
+ const VkDeviceCreateInfo create_info = {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ .queueCreateInfoCount = 1,
+ .pQueueCreateInfos = &queue_create_info,
+ .enabledExtensionCount = num_extensions,
+ .ppEnabledExtensionNames = extensions,
+ .pEnabledFeatures = &info.features,
+ };
+ result = vkCreateDevice(gpu, &create_info, nullptr, &device);
+ if (result != VK_SUCCESS)
+ die("vkCreateDevice", result);
+ vkDestroyDevice(device, nullptr);
+}
+
void GatherInfo(VulkanInfo* info) {
VkResult result;
uint32_t count;
@@ -173,36 +238,8 @@
die("vkEnumeratePhysicalDevices (data)", result);
info->gpus.resize(num_gpus);
- for (size_t gpu_idx = 0; gpu_idx < gpus.size(); gpu_idx++) {
- VkPhysicalDevice gpu = gpus[gpu_idx];
- GpuInfo& gpu_info = info->gpus.at(gpu_idx);
-
- vkGetPhysicalDeviceProperties(gpu, &gpu_info.properties);
- vkGetPhysicalDeviceMemoryProperties(gpu, &gpu_info.memory);
-
- vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
- gpu_info.queue_families.resize(count);
- vkGetPhysicalDeviceQueueFamilyProperties(
- gpu, &count, gpu_info.queue_families.data());
-
- result = vkEnumerateDeviceLayerProperties(gpu, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceLayerProperties (count)", result);
- do {
- gpu_info.layers.resize(count);
- result = vkEnumerateDeviceLayerProperties(gpu, &count,
- gpu_info.layers.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceLayerProperties (data)", result);
- gpu_info.layer_extensions.resize(gpu_info.layers.size());
-
- EnumerateDeviceExtensions(gpu, nullptr, &gpu_info.extensions);
- for (size_t i = 0; i < gpu_info.layers.size(); i++) {
- EnumerateDeviceExtensions(gpu, gpu_info.layers[i].layerName,
- &gpu_info.layer_extensions[i]);
- }
- }
+ for (size_t i = 0; i < gpus.size(); i++)
+ GatherGpuInfo(gpus[i], info->gpus.at(i));
vkDestroyInstance(instance, nullptr);
}
@@ -335,15 +372,15 @@
qprops.minImageTransferGranularity.width,
qprops.minImageTransferGranularity.height,
qprops.minImageTransferGranularity.depth);
+ }
- if (!info.extensions.empty()) {
- printf(" Extensions [%zu]:\n", info.extensions.size());
- PrintExtensions(info.extensions, " ");
- }
- if (!info.layers.empty()) {
- printf(" Layers [%zu]:\n", info.layers.size());
- PrintLayers(info.layers, info.layer_extensions, " ");
- }
+ if (!info.extensions.empty()) {
+ printf(" Extensions [%zu]:\n", info.extensions.size());
+ PrintExtensions(info.extensions, " ");
+ }
+ if (!info.layers.empty()) {
+ printf(" Layers [%zu]:\n", info.layers.size());
+ PrintLayers(info.layers, info.layer_extensions, " ");
}
}