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

Commit 9a9e06c4 authored by Juston Li's avatar Juston Li
Browse files

[Vulkan] Query global priority support for queue creation

Setting up a device queue with a global queue priority above the system
default requires sufficient privileges (SYS_NICE) otherwise queue
creation will fail.

SurfaceFlinger and system_server have SYS_NICE and will set priority to
REALTIME. SysUI and Launcher take that as an indication they should
request HIGH for better preemption strategy. However for upstream DRM
drivers, we currently lack a way to grant them granular access to HIGH
but not RT. For long term, the right way to do this is via drm specific
cgroup for scheduling controls however this is currently being worked
on upstream.

In the meantime, instead of fatally crashing, we can query the global
priorities supported before queue creation and if its not supported,
drop the priority request and log a warning.

Note this requires vkGetPhysicalDeviceQueueFamilyProperties2 which is
provided by Vulkan 1.1 while the global priority query can be safely
added to the pNext chain and will be ignored if
VK_EXT_global_priority_query isn't supported.

Bug: 343986434
Flag: com.android.graphics.hwui.flags.query_global_priority
Test: UI comes up debug.renderengine.backend=skiavkthreaded
Change-Id: I662c9ce3f3724e87690e25d260ee010340451c53
parent 7a9c9eec
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -50,6 +50,10 @@ constexpr bool skip_eglmanager_telemetry() {
constexpr bool resample_gainmap_regions() {
    return false;
}

constexpr bool query_global_priority() {
    return false;
}
}  // namespace hwui_flags
#endif

@@ -110,6 +114,7 @@ bool Properties::clipSurfaceViews = false;
bool Properties::hdr10bitPlus = false;
bool Properties::skipTelemetry = false;
bool Properties::resampleGainmapRegions = false;
bool Properties::queryGlobalPriority = false;

int Properties::timeoutMultiplier = 1;

@@ -187,6 +192,7 @@ bool Properties::load() {
    hdr10bitPlus = hwui_flags::hdr_10bit_plus();
    resampleGainmapRegions = base::GetBoolProperty("debug.hwui.resample_gainmap_regions",
                                                   hwui_flags::resample_gainmap_regions());
    queryGlobalPriority = hwui_flags::query_global_priority();

    timeoutMultiplier = android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
    skipTelemetry = base::GetBoolProperty(PROPERTY_SKIP_EGLMANAGER_TELEMETRY,
+1 −0
Original line number Diff line number Diff line
@@ -346,6 +346,7 @@ public:
    static bool hdr10bitPlus;
    static bool skipTelemetry;
    static bool resampleGainmapRegions;
    static bool queryGlobalPriority;

    static int timeoutMultiplier;

+10 −0
Original line number Diff line number Diff line
@@ -129,3 +129,13 @@ flag {
  description: "APIs that expose gainmap metadata corresponding to those defined in ISO 21496-1"
  bug: "349357636"
}

flag {
  name: "query_global_priority"
  namespace: "core_graphics"
  description: "Attempt to query whether the vulkan driver supports the requested global priority before queue creation."
  bug: "343986434"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
+70 −15
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ namespace uirenderer {
namespace renderthread {

// Not all of these are strictly required, but are all enabled if present.
static std::array<std::string_view, 21> sEnableExtensions{
static std::array<std::string_view, 23> sEnableExtensions{
        VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
        VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
        VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
@@ -65,6 +65,8 @@ static std::array<std::string_view, 21> sEnableExtensions{
        VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
        VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
        VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME,
        VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME,
        VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME,
        VK_EXT_DEVICE_FAULT_EXTENSION_NAME,
};

@@ -206,7 +208,7 @@ void VulkanManager::setupDevice(skgpu::VulkanExtensions& grExtensions,
    GET_INST_PROC(GetPhysicalDeviceFeatures2);
    GET_INST_PROC(GetPhysicalDeviceImageFormatProperties2);
    GET_INST_PROC(GetPhysicalDeviceProperties);
    GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
    GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties2);

    uint32_t gpuCount;
    LOG_ALWAYS_FATAL_IF(mEnumeratePhysicalDevices(mInstance, &gpuCount, nullptr));
@@ -225,21 +227,30 @@ void VulkanManager::setupDevice(skgpu::VulkanExtensions& grExtensions,

    // query to get the initial queue props size
    uint32_t queueCount = 0;
    mGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
    mGetPhysicalDeviceQueueFamilyProperties2(mPhysicalDevice, &queueCount, nullptr);
    LOG_ALWAYS_FATAL_IF(!queueCount);

    // now get the actual queue props
    std::unique_ptr<VkQueueFamilyProperties[]> queueProps(new VkQueueFamilyProperties[queueCount]);
    mGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, queueProps.get());
    std::unique_ptr<VkQueueFamilyProperties2[]>
            queueProps(new VkQueueFamilyProperties2[queueCount]);
    // query the global priority, this ignored if VK_EXT_global_priority isn't supported
    std::vector<VkQueueFamilyGlobalPriorityPropertiesEXT> queuePriorityProps(queueCount);
    for (uint32_t i = 0; i < queueCount; i++) {
        queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT;
        queuePriorityProps[i].pNext = nullptr;
        queueProps[i].pNext = &queuePriorityProps[i];
    }
    mGetPhysicalDeviceQueueFamilyProperties2(mPhysicalDevice, &queueCount, queueProps.get());

    constexpr auto kRequestedQueueCount = 2;

    // iterate to find the graphics queue
    mGraphicsQueueIndex = queueCount;
    for (uint32_t i = 0; i < queueCount; i++) {
        if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
        if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
            mGraphicsQueueIndex = i;
            LOG_ALWAYS_FATAL_IF(queueProps[i].queueCount < kRequestedQueueCount);
            LOG_ALWAYS_FATAL_IF(
                    queueProps[i].queueFamilyProperties.queueCount < kRequestedQueueCount);
            break;
        }
    }
@@ -327,6 +338,15 @@ void VulkanManager::setupDevice(skgpu::VulkanExtensions& grExtensions,
        tailPNext = &formatFeatures->pNext;
    }

    VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT* globalPriorityQueryFeatures =
            new VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT;
    globalPriorityQueryFeatures->sType =
            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT;
    globalPriorityQueryFeatures->pNext = nullptr;
    globalPriorityQueryFeatures->globalPriorityQuery = false;
    *tailPNext = globalPriorityQueryFeatures;
    tailPNext = &globalPriorityQueryFeatures->pNext;

    // query to get the physical device features
    mGetPhysicalDeviceFeatures2(mPhysicalDevice, &features);
    // this looks like it would slow things down,
@@ -341,24 +361,59 @@ void VulkanManager::setupDevice(skgpu::VulkanExtensions& grExtensions,

    if (Properties::contextPriority != 0 &&
        grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
        memset(&queuePriorityCreateInfo, 0, sizeof(VkDeviceQueueGlobalPriorityCreateInfoEXT));
        queuePriorityCreateInfo.sType =
                VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT;
        queuePriorityCreateInfo.pNext = nullptr;
        VkQueueGlobalPriorityEXT globalPriority;
        switch (Properties::contextPriority) {
            case EGL_CONTEXT_PRIORITY_LOW_IMG:
                queuePriorityCreateInfo.globalPriority = VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT;
                globalPriority = VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT;
                break;
            case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
                queuePriorityCreateInfo.globalPriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT;
                globalPriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT;
                break;
            case EGL_CONTEXT_PRIORITY_HIGH_IMG:
                queuePriorityCreateInfo.globalPriority = VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT;
                globalPriority = VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT;
                break;
            default:
                LOG_ALWAYS_FATAL("Unsupported context priority");
        }

        // check if the requested priority is reported by the query
        bool attachGlobalPriority = false;
        if (uirenderer::Properties::queryGlobalPriority &&
            globalPriorityQueryFeatures->globalPriorityQuery) {
            for (uint32_t i = 0; i < queuePriorityProps[mGraphicsQueueIndex].priorityCount; i++) {
                if (queuePriorityProps[mGraphicsQueueIndex].priorities[i] == globalPriority) {
                    attachGlobalPriority = true;
                    break;
                }
            }
        } else {
            // Querying is not supported so attempt queue creation with requested priority anyways
            // If the priority turns out not to be supported, the driver *may* fail with
            // VK_ERROR_NOT_PERMITTED_KHR
            attachGlobalPriority = true;
        }

        if (attachGlobalPriority) {
            memset(&queuePriorityCreateInfo, 0, sizeof(VkDeviceQueueGlobalPriorityCreateInfoEXT));
            queuePriorityCreateInfo.sType =
                    VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT;
            queuePriorityCreateInfo.pNext = nullptr;
            queuePriorityCreateInfo.globalPriority = globalPriority;
            queueNextPtr = &queuePriorityCreateInfo;
        } else {
            // If globalPriorityQuery is enabled, attempting queue creation with an unsupported
            // priority will return VK_ERROR_INITIALIZATION_FAILED.
            //
            // SysUI and Launcher will request HIGH when SF has RT but it is a known issue that
            // upstream drm drivers currently lack a way to grant them the granular privileges
            // they need for HIGH (but not RT) so they will fail queue creation.
            // For now, drop the unsupported global priority request so that queue creation
            // succeeds.
            //
            // Once that is fixed, this should probably be a fatal error indicating an improper
            // request or an app needs to get the correct privileges.
            ALOGW("Requested context priority is not supported by the queue");
        }
    }

    const VkDeviceQueueCreateInfo queueInfo = {
+1 −1
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ private:
    VkPtr<PFN_vkDestroyInstance> mDestroyInstance;
    VkPtr<PFN_vkEnumeratePhysicalDevices> mEnumeratePhysicalDevices;
    VkPtr<PFN_vkGetPhysicalDeviceProperties> mGetPhysicalDeviceProperties;
    VkPtr<PFN_vkGetPhysicalDeviceQueueFamilyProperties> mGetPhysicalDeviceQueueFamilyProperties;
    VkPtr<PFN_vkGetPhysicalDeviceQueueFamilyProperties2> mGetPhysicalDeviceQueueFamilyProperties2;
    VkPtr<PFN_vkGetPhysicalDeviceFeatures2> mGetPhysicalDeviceFeatures2;
    VkPtr<PFN_vkGetPhysicalDeviceImageFormatProperties2> mGetPhysicalDeviceImageFormatProperties2;
    VkPtr<PFN_vkCreateDevice> mCreateDevice;