Mali and Vulkan on Linux fbdev

Greetings everyone,

Is there any example on how to execute a Vulkan example, with Mali drivers, on Linux using the fbdev interface ?

I'm just wondering how the display initialisation and surface creation should be handled on such platforms, with Vulkan.

  • This is done through VK_KHR_display extension. Instead of creating a VkSurfaceKHR from X11/Wayland window handles, there is a special API to query display modes and you can create a VkSurfaceKHR directly from that API.

  • !! Thanks for the answer and these precious informations !

    Will the code described in the aforementioned extension proposal text do the trick ?

    The extension proposal text being :

    http://vulkan-spec-chunked.ahcox.com/apes04.html

    They seem to suggest using this code :

        extern VkBool32 ModeMatchesMyCriteria(const VkDisplayModePropertiesKHR *m);
        extern VkInstance instance;
        extern VkPhysicalDevice physDevice;
        extern VkSurfaceKHR surface;
    
        uint32_t displayCount, planeCount, i, j, k;
        VkDisplayPropertiesKHR* pDisplayProps;
        VkDisplayPlanePropertiesKHR* pPlaneProps;
        VkDisplayModeKHR myMode = VK_NULL_HANDLE;
        VkDisplayKHR myDisplay = VK_NULL_HANDLE;
        uint32_t bestPlane = UINT32_MAX;
        VkDisplayPlaneAlphaFlagBitsKHR alphaMode = 0;
        PFN_vkGetPhysicalDeviceDisplayPropertiesKHR pfnGetPhysicalDeviceDisplayPropertiesKHR;
        PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR pfnGetPhysicalDeviceDisplayPlanePropertiesKHR;
        PFN_vkGetDisplayModePropertiesKHR pfnGetDisplayModePropertiesKHR;
        PFN_vkGetDisplayPlaneCapabilitiesKHR pfnGetDisplayPlaneCapabilitiesKHR;
        PFN_vkGetDisplayPlaneSupportedDisplaysKHR pfnGetDisplayPlaneSupportedDisplaysKHR;
        PFN_vkCreateDisplayPlaneSurfaceKHR pfnCreateDisplayPlaneSurfaceKHR;
    
        pfnGetPhysicalDeviceDisplayPropertiesKHR =
            (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)
            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR");
        pfnGetPhysicalDeviceDisplayPlanePropertiesKHR =
            (PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)
            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
        pfnGetDisplayModePropertiesKHR =
            (PFN_vkGetDisplayModePropertiesKHR)
            vkGetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR");
        pfnGetDisplayPlaneCapabilitiesKHR =
            (PFN_vkGetDisplayPlaneCapabilitiesKHR)
            vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR");
        pfnGetDisplayPlaneSupportedDisplaysKHR =
            (PFN_vkGetDisplayPlaneSupportedDisplaysKHR)
            vkGetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR");
        pfnCreateDisplayPlaneSurfaceKHR =
            (PFN_vkCreateDisplayPlaneSurfaceKHR)
            vkGetInstanceProcAddr(instance, "vkCreateDisplayPlaneSurfaceKHR");
    
        // Get a list of displays on a physical device
        displayCount = 0;
        pfnGetPhysicalDeviceDisplayPropertiesKHR(physDevice, &displayCount, NULL);
    
        pDisplayProps = (VkDisplayPropertiesKHR*)malloc(sizeof(VkDisplayPropertiesKHR) * displayCount);
        pfnGetPhysicalDeviceDisplayPropertiesKHR(physDevice, &displayCount, pDisplayProps);
    
        // Get a list of display planes on a physical device
        planeCount = 0;
        pfnGetPhysicalDeviceDisplayPlanePropertiesKHR(physDevice, &planeCount, NULL);
        pPlaneProps = (VkDisplayPlanePropertiesKHR*)malloc(sizeof(VkDisplayPlanePropertiesKHR) * planeCount);
        pfnGetPhysicalDeviceDisplayPlanePropertiesKHR(physDevice, &planeCount, pPlaneProps);
    
        // Get the list of pModes each display supports
        for (i = 0; i < displayCount; ++i)
        {
            VkDisplayKHR display = pDisplayProps[i].display;
            VkDisplayModePropertiesKHR* pModes;
            uint32_t modeCount;
    
            vkGetDisplayModePropertiesKHR(physDevice, display, &modeCount, NULL);
    
            pModes = (VkDisplayModePropertiesKHR*)malloc(sizeof(VkDisplayModePropertiesKHR) * modeCount);
            vkGetDisplayModePropertiesKHR(physDevice, display, &modeCount, pModes);
    
            myMode = VK_NULL_HANDLE;
            for (j = 0; j < modeCount; ++j)
            {
                const VkDisplayModePropertiesKHR* mode = &pModes[i];
    
                if (ModeMatchesMyCriteria(mode))
                {
                    myMode = mode->displayMode;
                    break;
                }
            }
    
            free(pModes);
    
            // If there are no useable pModes found then check the next display.
            if (myMode == VK_NULL_HANDLE)
                continue;
    
            // Find a plane that matches these criteria, in order of preference:
            // -Is compatible with the chosen display + mode.
            // -Isn't currently bound to another display.
            // -Supports per-pixel alpha, if possible.
            for (j = 0; j < planeCount; ++j)
            {
                uint32_t supportedCount = 0;
                VkDisplayKHR* pSupportedDisplays;
                VkDisplayPlaneCapabilitiesKHR planeCaps;
                // See if the plane is compatible with the current display.
                pfnGetDisplayPlaneSupportedDisplaysKHR(physDevice, j, &supportedCount, NULL);
    
                // Plane doesn't support any displays.  This might happen on a card
                // that has a fixed mapping between planes and connectors when no
                // displays are currently attached to this plane's conector, for
                // example.
                if (supportedCount == 0)
                    continue;
    
                pSupportedDisplays = (VkDisplayKHR*)malloc(sizeof(VkDisplayKHR) * supportedCount);
                pfnGetDisplayPlaneSupportedDisplaysKHR(physDevice, j, &supportedCount, pSupportedDisplays);
    
                for (k = 0; k < supportedCount; ++k)
                    if (pSupportedDisplays[k] == display) {
                        // If no supported plane has yet been found, this is
                        // currently the best available plane.
                        if (bestPlane == UINT32_MAX)
                            bestPlane = j;
                        break;
                    }
    
                // If the plane can't be used with the chosen display, keep looking.
                // Each display must have at least one compatible plane.
                if (k == supportedCount)
                    continue;
    
                // If the plane passed the above test and is currently bound to the
                // desired display, or is not in use, it is the best plane found so
                // far.
                if ((pPlaneProps[j].currentDisplay == VK_NULL_HANDLE) &&
                    (pPlaneProps[j].currentDisplay == display))
                    bestPlane = j;
                else
                    continue;
    
                pfnGetDisplayPlaneCapabilitiesKHR(physDevice, myMode, j, &planeCaps);
    
                // Prefer a plane that supports per-pixel alpha.
                if (planeCaps.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR)
                {
                    // This is the perfect plane for the given criteria.  Use it.
                    bestPlane = j;
                    alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
                    break;
                }
            }
        }
    
        free(pDisplayProps);
    
        if (myDisplay == VK_NULL_HANDLE || myMode == VK_NULL_HANDLE) {
            // No suitable display + mode could be found.  Abort.
            abort();
        } else {
            // Success.  Create a VkSurfaceKHR object for this plane.
            const VkDisplaySurfaceCreateInfoKHR createInfo =
            {
                VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,  // sType
                NULL,                                               // pNext
                0,                                                  // flags
                myMode,                                             // displayMode
                bestPlane,                                          // planeIndex
                pPlaneProps[bestPlane].currentStackIndex,           // planeStackIndex
                VK_SURFACE_TRANSFORM_IDENTITY_KHR,                  // transform
                1.0f,                                               // globalAlpha
                alphaMode,                                          // alphaMode
                ...
            }
    
            pfnCreateDisplayPlaneSurfaceKHR(instance, &createInfo, NULL, &surface);
        }

    I guess that the key in creating the surface using this method is within vkCreateDisplayPlaneSurfaceKHR ?

More questions in this forum