Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b147127b authored by Jesse Hall's avatar Jesse Hall
Browse files

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)
parent 57f7f8c1
Loading
Loading
Loading
Loading
+23 −2
Original line number Diff line number Diff line
@@ -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
@@ -396,6 +402,13 @@ PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
                  : 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 @@ InstanceExtension InstanceExtensionFromName(const char* name) {
    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
+99 −12
Original line number Diff line number Diff line
@@ -268,6 +268,7 @@ struct Instance {
    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 Instance {

    struct {
        VkInstance instance;
        InstanceExtensionSet supported_extensions;
        DriverDispatchTable dispatch;
        uint32_t num_physical_devices;
    } drv;  // may eventually be an array
@@ -582,6 +582,9 @@ VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
        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 @@ VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
            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 @@ void GetPhysicalDeviceSparseImageFormatProperties_Bottom(

VKAPI_ATTR
VkResult EnumerateDeviceExtensionProperties_Bottom(
    VkPhysicalDevice /*pdev*/,
    VkPhysicalDevice gpu,
    const char* layer_name,
    uint32_t* properties_count,
    VkExtensionProperties* properties) {
@@ -695,7 +729,26 @@ VkResult EnumerateDeviceExtensionProperties_Bottom(
    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 @@ VkResult EnumerateDeviceLayerProperties_Bottom(VkPhysicalDevice /*pdev*/,
}

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 @@ VkResult CreateDevice_Bottom(VkPhysicalDevice pdev,
        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 @@ VkResult CreateDevice_Bottom(VkPhysicalDevice pdev,
    // 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 @@ VkResult CreateDevice_Bottom(VkPhysicalDevice pdev,
    // 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)) {
+10 −0
Original line number Diff line number Diff line
@@ -31,6 +31,13 @@ enum InstanceExtension {
};
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 @@ class LayerRef {
    PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;
    PFN_vkGetDeviceProcAddr GetGetDeviceProcAddr() const;

    bool SupportsExtension(const char* name) const;

   private:
    Layer* layer_;
};
@@ -166,6 +175,7 @@ LayerRef GetInstanceLayerRef(const char* name);
LayerRef GetDeviceLayerRef(const char* name);

InstanceExtension InstanceExtensionFromName(const char* name);
DeviceExtension DeviceExtensionFromName(const char* name);

}  // namespace vulkan

+13 −5
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ struct VkInstance_T {
    VkAllocationCallbacks allocator;
    VkPhysicalDevice_T physical_device;
    uint64_t next_callback_handle;
    bool debug_report_enabled;
};

struct VkQueue_T {
@@ -251,13 +250,15 @@ VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
    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 @@ void GetPhysicalDeviceMemoryProperties(
// 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 @@ VkResult CreateDevice(VkPhysicalDevice physical_device,
    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;
}
+75 −38
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ namespace {
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 @@ void EnumerateDeviceExtensions(VkPhysicalDevice gpu,
        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 @@ void GatherInfo(VulkanInfo* info) {
        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,6 +372,7 @@ void PrintGpuInfo(const GpuInfo& info) {
            qprops.minImageTransferGranularity.width,
            qprops.minImageTransferGranularity.height,
            qprops.minImageTransferGranularity.depth);
    }

    if (!info.extensions.empty()) {
        printf("    Extensions [%zu]:\n", info.extensions.size());
@@ -345,7 +383,6 @@ void PrintGpuInfo(const GpuInfo& info) {
        PrintLayers(info.layers, info.layer_extensions, "      ");
    }
}
}

void PrintInfo(const VulkanInfo& info) {
    std::ostringstream strbuf;