Introduce VK_KHR_display support for i.MX8 devices

The eglfs_viv backend has Vulkan support now. While the support code is
common (lives in api/vulkan), we will not expose this for any other integration
yet, without the appropriate testing.

While putting this to eglfs seems unintuitive at first, it turns out that
for Vivante in particular this is very useful, since we can rely on the existing
framebuffer device infrastructure to solve certain problems (like the lack of
vsync)

The VK_KHR_display implementation of Vivante currently exhibits all the known issues
of the old, fbdev-style EGL plumbing (presumably since it lives on top of that):

- No vsync. This can be fixed by setting QT_QPA_EGLFS_FORCEVSYNC.

- May need a manual call to fbset to set the correct resolution before
launching the Qt app.

- And of course it lacks all the multi-screen features provided by drm.

- Plus, it seems the swapchain only supports a min/max buffer count of 1. This
needs special handling in QRhi since until now we assumed that there was always
at least 2 buffers available.

[ChangeLog][Platform Specific Changes][Linux] Vulkan is now supported by eglfs
(eglfs_viv backend) on i.MX8 devices with the Vivante graphics stack. This is done
via VK_KHR_display so no windowing system is required.

Task-number: QTBUG-78754
Change-Id: I7530aa026d4b904b9de83f9bdbdc4897ae770e71
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
This commit is contained in:
Laszlo Agocs 2020-01-17 15:06:47 +01:00
parent dd23313d66
commit e0e7c42a19
14 changed files with 602 additions and 9 deletions

View File

@ -1351,8 +1351,8 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
quint32 actualSwapChainBufferCount = 0;
err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, nullptr);
if (err != VK_SUCCESS || actualSwapChainBufferCount < 2) {
qWarning("Failed to get swapchain images: %d (count=%u)", err, actualSwapChainBufferCount);
if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
qWarning("Failed to get swapchain images: %d", err);
return false;
}
@ -1528,7 +1528,8 @@ void QRhiVulkan::releaseSwapChainResources(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
QVkSwapChain *swapChainD = QRHI_RES(QVkSwapChain, swapChain);
QVkSwapChain::FrameResources &frame(swapChainD->frameRes[swapChainD->currentFrameSlot]);
const int frameResIndex = swapChainD->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
QVkSwapChain::FrameResources &frame(swapChainD->frameRes[frameResIndex]);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
if (!frame.imageAcquired) {
@ -1571,7 +1572,7 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
// will make B wait for A's frame 0 commands, so if a resource is written
// in B's frame or when B checks for pending resource releases, that won't
// mess up A's in-flight commands (as they are not in flight anymore).
waitCommandCompletion(int(swapChainD->currentFrameSlot));
waitCommandCompletion(frameResIndex);
// Now is the time to read the timestamps for the previous frame for this slot.
if (frame.timestampQueryIndex >= 0) {
@ -1606,7 +1607,7 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
// when profiling is enabled, pick a free query (pair) from the pool
int timestampQueryIdx = -1;
if (profilerPrivateOrNull()) {
if (profilerPrivateOrNull() && swapChainD->bufferCount > 1) { // no timestamps if not having at least 2 frames in flight
for (int i = 0; i < timestampQueryPoolMap.count(); ++i) {
if (!timestampQueryPoolMap.testBit(i)) {
timestampQueryPoolMap.setBit(i);
@ -1648,7 +1649,8 @@ QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain, QRhi::EndFram
recordPrimaryCommandBuffer(&swapChainD->cbWrapper);
QVkSwapChain::FrameResources &frame(swapChainD->frameRes[swapChainD->currentFrameSlot]);
int frameResIndex = swapChainD->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
QVkSwapChain::FrameResources &frame(swapChainD->frameRes[frameResIndex]);
QVkSwapChain::ImageResources &image(swapChainD->imageRes[swapChainD->currentImageIndex]);
if (image.lastUse != QVkSwapChain::ImageResources::ScImageUseRender) {
@ -1860,7 +1862,8 @@ QRhi::FrameOpResult QRhiVulkan::endAndSubmitPrimaryCommandBuffer(VkCommandBuffer
void QRhiVulkan::waitCommandCompletion(int frameSlot)
{
for (QVkSwapChain *sc : qAsConst(swapchains)) {
QVkSwapChain::FrameResources &frame(sc->frameRes[frameSlot]);
const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
if (frame.cmdFenceWaitable) {
df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
df->vkResetFences(dev, 1, &frame.cmdFence);

View File

@ -23,4 +23,13 @@ qtConfig(opengl) {
$$PWD/qeglfscontext_p.h
}
qtConfig(vulkan) {
SOURCES += \
$$PWD/vulkan/qeglfsvulkaninstance.cpp \
$$PWD/vulkan/qeglfsvulkanwindow.cpp
HEADERS += \
$$PWD/vulkan/qeglfsvulkaninstance_p.h \
$$PWD/vulkan/qeglfsvulkanwindow_p.h
}
INCLUDEPATH += $$PWD

View File

@ -381,6 +381,14 @@ void *QEglFSDeviceIntegration::wlDisplay() const
return nullptr;
}
#if QT_CONFIG(vulkan)
QPlatformVulkanInstance *QEglFSDeviceIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
{
Q_UNUSED(instance);
return nullptr;
}
#endif
EGLConfig QEglFSDeviceIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
{
class Chooser : public QEglConfigChooser {

View File

@ -108,6 +108,10 @@ public:
virtual void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen);
virtual void *wlDisplay() const;
#if QT_CONFIG(vulkan)
virtual QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance);
#endif
static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format);
};

View File

@ -247,6 +247,13 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf
}
#endif // QT_NO_OPENGL
#if QT_CONFIG(vulkan)
QPlatformVulkanInstance *QEglFSIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
{
return qt_egl_device_integration()->createPlatformVulkanInstance(instance);
}
#endif
bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
// We assume that devices will have more and not less capabilities
@ -283,7 +290,8 @@ enum ResourceType {
NativeDisplay,
XlibDisplay,
WaylandDisplay,
EglSurface
EglSurface,
VkSurface
};
static int resourceType(const QByteArray &key)
@ -296,7 +304,8 @@ static int resourceType(const QByteArray &key)
QByteArrayLiteral("nativedisplay"),
QByteArrayLiteral("display"),
QByteArrayLiteral("server_wl_display"),
QByteArrayLiteral("eglsurface")
QByteArrayLiteral("eglsurface"),
QByteArrayLiteral("vksurface")
};
const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
const QByteArray *result = std::find(names, end, key);
@ -364,6 +373,12 @@ void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWi
if (window && window->handle())
result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->surface());
break;
#if QT_CONFIG(vulkan)
case VkSurface:
if (window && window->handle() && window->surfaceType() == QSurface::VulkanSurface)
result = static_cast<QEglFSWindow *>(window->handle())->vulkanSurfacePtr();
break;
#endif
default:
break;
}

View File

@ -85,6 +85,9 @@ public:
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
#endif
#if QT_CONFIG(vulkan)
QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
#endif
bool hasCapability(QPlatformIntegration::Capability cap) const override;

View File

@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE
class QOpenGLCompositorBackingStore;
class QPlatformTextureList;
#ifndef QT_NO_OPENGL
class Q_EGLFS_EXPORT QEglFSWindow : public QPlatformWindow, public QOpenGLCompositorWindow
#else
@ -96,6 +97,9 @@ public:
EGLNativeWindowType eglWindow() const;
EGLSurface surface() const;
QEglFSScreen *screen() const override;
#if QT_CONFIG(vulkan)
virtual void *vulkanSurfacePtr() { return nullptr; }
#endif
bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); }

View File

@ -0,0 +1,280 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qeglfsvulkaninstance_p.h"
#include "qeglfswindow_p.h"
#include "qeglfshooks_p.h"
#include <QLoggingCategory>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcEglDevDebug)
QEglFSVulkanInstance::QEglFSVulkanInstance(QVulkanInstance *instance)
: m_instance(instance)
{
loadVulkanLibrary(QStringLiteral("vulkan"));
}
void QEglFSVulkanInstance::createOrAdoptInstance()
{
qCDebug(qLcEglDevDebug, "Creating Vulkan instance for VK_KHR_display");
const QByteArray extName = QByteArrayLiteral("VK_KHR_display");
initInstance(m_instance, { extName });
if (!m_vkInst)
return;
if (!enabledExtensions().contains(extName)) {
qWarning("Failed to enable VK_KHR_display extension");
return;
}
#if VK_KHR_display
m_getPhysicalDeviceDisplayPropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)
m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceDisplayPropertiesKHR");
m_getDisplayModePropertiesKHR = (PFN_vkGetDisplayModePropertiesKHR)
m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayModePropertiesKHR");
m_getPhysicalDeviceDisplayPlanePropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)
m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
m_getDisplayPlaneSupportedDisplaysKHR = (PFN_vkGetDisplayPlaneSupportedDisplaysKHR)
m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayPlaneSupportedDisplaysKHR");
m_getDisplayPlaneCapabilitiesKHR = (PFN_vkGetDisplayPlaneCapabilitiesKHR)
m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayPlaneCapabilitiesKHR");
m_createDisplayPlaneSurfaceKHR = (PFN_vkCreateDisplayPlaneSurfaceKHR)
m_vkGetInstanceProcAddr(m_vkInst, "vkCreateDisplayPlaneSurfaceKHR");
#endif
m_enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)
m_vkGetInstanceProcAddr(m_vkInst, "vkEnumeratePhysicalDevices");
// Use for first physical device, unless overridden by QT_VK_PHYSICAL_DEVICE_INDEX.
// This behavior matches what the Vulkan backend of QRhi would do.
uint32_t physDevCount = 0;
m_enumeratePhysicalDevices(m_vkInst, &physDevCount, nullptr);
if (!physDevCount) {
qWarning("No physical devices");
return;
}
QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
VkResult err = m_enumeratePhysicalDevices(m_vkInst, &physDevCount, physDevs.data());
if (err != VK_SUCCESS || !physDevCount) {
qWarning("Failed to enumerate physical devices: %d", err);
return;
}
if (qEnvironmentVariableIsSet("QT_VK_PHYSICAL_DEVICE_INDEX")) {
int requestedPhysDevIndex = qEnvironmentVariableIntValue("QT_VK_PHYSICAL_DEVICE_INDEX");
if (requestedPhysDevIndex >= 0 && uint32_t(requestedPhysDevIndex) < physDevCount)
m_physDev = physDevs[requestedPhysDevIndex];
}
if (m_physDev == VK_NULL_HANDLE)
m_physDev = physDevs[0];
}
bool QEglFSVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
QWindow *window)
{
Q_UNUSED(physicalDevice);
Q_UNUSED(queueFamilyIndex);
Q_UNUSED(window);
return true;
}
VkSurfaceKHR QEglFSVulkanInstance::createSurface(QEglFSWindow *window)
{
#if VK_KHR_display
qCDebug(qLcEglDevDebug, "Creating VkSurfaceKHR via VK_KHR_display for window %p", (void *) window);
if (!m_physDev) {
qWarning("No physical device, cannot create surface");
return VK_NULL_HANDLE;
}
uint32_t displayCount = 0;
VkResult err = m_getPhysicalDeviceDisplayPropertiesKHR(m_physDev, &displayCount, nullptr);
if (err != VK_SUCCESS) {
qWarning("Failed to get display properties: %d", err);
return VK_NULL_HANDLE;
}
qCDebug(qLcEglDevDebug, "Display count: %u", displayCount);
QVarLengthArray<VkDisplayPropertiesKHR, 4> displayProps(displayCount);
m_getPhysicalDeviceDisplayPropertiesKHR(m_physDev, &displayCount, displayProps.data());
VkDisplayKHR display = VK_NULL_HANDLE;
VkDisplayModeKHR displayMode = VK_NULL_HANDLE;
uint32_t width = 0;
uint32_t height = 0;
for (uint32_t i = 0; i < displayCount; ++i) {
const VkDisplayPropertiesKHR &disp(displayProps[i]);
qCDebug(qLcEglDevDebug, "Display #%u:\n display: %p\n name: %s\n dimensions: %ux%u\n resolution: %ux%u",
i, (void *) disp.display, disp.displayName,
disp.physicalDimensions.width, disp.physicalDimensions.height,
disp.physicalResolution.width, disp.physicalResolution.height);
// Just pick the first display and the first mode.
if (i == 0)
display = disp.display;
uint32_t modeCount = 0;
if (m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, nullptr) != VK_SUCCESS) {
qWarning("Failed to get modes for display");
continue;
}
QVarLengthArray<VkDisplayModePropertiesKHR, 16> modeProps(modeCount);
m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, modeProps.data());
for (uint32_t j = 0; j < modeCount; ++j) {
const VkDisplayModePropertiesKHR &mode(modeProps[j]);
qCDebug(qLcEglDevDebug, " Mode #%u:\n mode: %p\n visibleRegion: %ux%u\n refreshRate: %u",
j, (void *) mode.displayMode,
mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height,
mode.parameters.refreshRate);
if (j == 0) {
displayMode = mode.displayMode;
width = mode.parameters.visibleRegion.width;
height = mode.parameters.visibleRegion.height;
}
}
}
if (display == VK_NULL_HANDLE || displayMode == VK_NULL_HANDLE) {
qWarning("Failed to choose display and mode");
return VK_NULL_HANDLE;
}
uint32_t planeCount = 0;
err = m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, nullptr);
if (err != VK_SUCCESS) {
qWarning("Failed to get plane properties: %d", err);
return VK_NULL_HANDLE;
}
qCDebug(qLcEglDevDebug, "Plane count: %u", planeCount);
QVarLengthArray<VkDisplayPlanePropertiesKHR, 4> planeProps(planeCount);
m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, planeProps.data());
uint32_t planeIndex = UINT_MAX;
for (uint32_t i = 0; i < planeCount; ++i) {
uint32_t supportedDisplayCount = 0;
err = m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, nullptr);
if (err != VK_SUCCESS) {
qWarning("Failed to query supported displays for plane: %d", err);
return VK_NULL_HANDLE;
}
QVarLengthArray<VkDisplayKHR, 4> supportedDisplays(supportedDisplayCount);
m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, supportedDisplays.data());
qCDebug(qLcEglDevDebug, "Plane #%u supports %u displays, currently bound to display %p",
i, supportedDisplayCount, (void *) planeProps[i].currentDisplay);
VkDisplayPlaneCapabilitiesKHR caps;
err = m_getDisplayPlaneCapabilitiesKHR(m_physDev, displayMode, i, &caps);
if (err != VK_SUCCESS) {
qWarning("Failed to query plane capabilities: %d", err);
return VK_NULL_HANDLE;
}
qCDebug(qLcEglDevDebug, " supportedAlpha: %d (1=no, 2=global, 4=per pixel, 8=per pixel premul)\n"
" minSrc=%d, %d %ux%u\n"
" maxSrc=%d, %d %ux%u\n"
" minDst=%d, %d %ux%u\n"
" maxDst=%d, %d %ux%u",
int(caps.supportedAlpha),
caps.minSrcPosition.x, caps.minSrcPosition.y, caps.minSrcExtent.width, caps.minSrcExtent.height,
caps.maxSrcPosition.x, caps.maxSrcPosition.y, caps.maxSrcExtent.width, caps.maxSrcExtent.height,
caps.minDstPosition.x, caps.minDstPosition.y, caps.minDstExtent.width, caps.minDstExtent.height,
caps.maxDstPosition.x, caps.maxDstPosition.y, caps.maxDstExtent.width, caps.maxDstExtent.height);
// if the plane is not in use and supports our chosen display, use that plane
if (supportedDisplays.contains(display)
&& (planeProps[i].currentDisplay == VK_NULL_HANDLE || planeProps[i].currentDisplay == display))
{
planeIndex = i;
}
}
if (planeIndex == UINT_MAX) {
qWarning("Failed to find a suitable plane");
return VK_NULL_HANDLE;
}
qCDebug(qLcEglDevDebug, "Using plane #%u", planeIndex);
VkDisplaySurfaceCreateInfoKHR surfaceCreateInfo = {};
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.displayMode = displayMode;
surfaceCreateInfo.planeIndex = planeIndex;
surfaceCreateInfo.planeStackIndex = planeProps[planeIndex].currentStackIndex;
surfaceCreateInfo.transform = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
surfaceCreateInfo.globalAlpha = 1.0f;
surfaceCreateInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
surfaceCreateInfo.imageExtent = { width, height };
VkSurfaceKHR surface = VK_NULL_HANDLE;
err = m_createDisplayPlaneSurfaceKHR(m_vkInst, &surfaceCreateInfo, nullptr, &surface);
if (err != VK_SUCCESS || surface == VK_NULL_HANDLE) {
qWarning("Failed to create surface: %d", err);
return VK_NULL_HANDLE;
}
qCDebug(qLcEglDevDebug, "Created surface %p", (void *) surface);
return surface;
#else
Q_UNUSED(window);
qWarning("VK_KHR_display support was not compiled in, cannot create surface");
return VK_NULL_HANDLE;
#endif
}
void QEglFSVulkanInstance::presentAboutToBeQueued(QWindow *window)
{
// support QT_QPA_EGLFS_FORCEVSYNC (i.MX8 with eglfs_viv)
qt_egl_device_integration()->waitForVSync(window->handle());
}
QT_END_NAMESPACE

View File

@ -0,0 +1,88 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QEGLFSVULKANINSTANCE_H
#define QEGLFSVULKANINSTANCE_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qeglfsglobal_p.h"
#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
QT_BEGIN_NAMESPACE
class QEglFSWindow;
class Q_EGLFS_EXPORT QEglFSVulkanInstance : public QBasicPlatformVulkanInstance
{
public:
QEglFSVulkanInstance(QVulkanInstance *instance);
void createOrAdoptInstance() override;
bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override;
void presentAboutToBeQueued(QWindow *window) override;
VkSurfaceKHR createSurface(QEglFSWindow *window);
private:
QVulkanInstance *m_instance;
VkPhysicalDevice m_physDev = VK_NULL_HANDLE;
PFN_vkEnumeratePhysicalDevices m_enumeratePhysicalDevices = nullptr;
#if VK_KHR_display
PFN_vkGetPhysicalDeviceDisplayPropertiesKHR m_getPhysicalDeviceDisplayPropertiesKHR = nullptr;
PFN_vkGetDisplayModePropertiesKHR m_getDisplayModePropertiesKHR = nullptr;
PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR m_getPhysicalDeviceDisplayPlanePropertiesKHR = nullptr;
PFN_vkGetDisplayPlaneSupportedDisplaysKHR m_getDisplayPlaneSupportedDisplaysKHR = nullptr;
PFN_vkGetDisplayPlaneCapabilitiesKHR m_getDisplayPlaneCapabilitiesKHR = nullptr;
PFN_vkCreateDisplayPlaneSurfaceKHR m_createDisplayPlaneSurfaceKHR = nullptr;
#endif
};
QT_END_NAMESPACE
#endif

View File

@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qeglfsvulkanwindow_p.h"
QT_BEGIN_NAMESPACE
QEglFSVulkanWindow::QEglFSVulkanWindow(QWindow *window)
: QEglFSWindow(window),
m_surface(VK_NULL_HANDLE)
{
}
QEglFSVulkanWindow::~QEglFSVulkanWindow()
{
if (m_surface) {
QVulkanInstance *inst = window()->vulkanInstance();
if (inst)
static_cast<QEglFSVulkanInstance *>(inst->handle())->destroySurface(m_surface);
}
}
void *QEglFSVulkanWindow::vulkanSurfacePtr()
{
if (m_surface)
return &m_surface;
QVulkanInstance *inst = window()->vulkanInstance();
if (!inst) {
qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?");
return nullptr;
}
QEglFSVulkanInstance *eglfsInst = static_cast<QEglFSVulkanInstance *>(inst->handle());
m_surface = eglfsInst->createSurface(this);
return &m_surface;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QEGLFSVULKANWINDOW_H
#define QEGLFSVULKANWINDOW_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qeglfsglobal_p.h"
#include "qeglfswindow_p.h"
#include "qeglfsvulkaninstance_p.h"
QT_BEGIN_NAMESPACE
class Q_EGLFS_EXPORT QEglFSVulkanWindow : public QEglFSWindow
{
public:
QEglFSVulkanWindow(QWindow *window);
~QEglFSVulkanWindow();
void *vulkanSurfacePtr() override;
private:
VkSurfaceKHR m_surface;
};
QT_END_NAMESPACE
#endif

View File

@ -41,6 +41,11 @@
#include <EGL/eglvivante.h>
#include <QDebug>
#if QT_CONFIG(vulkan)
#include "private/qeglfsvulkaninstance_p.h"
#include "private/qeglfsvulkanwindow_p.h"
#endif
#ifdef Q_OS_INTEGRITY
extern "C" void VivanteInit(void);
#endif
@ -97,4 +102,20 @@ void QEglFSVivIntegration::destroyNativeWindow(EGLNativeWindowType window)
fbDestroyWindow(window);
}
#if QT_CONFIG(vulkan)
QEglFSWindow *QEglFSVivIntegration::createWindow(QWindow *window) const
{
if (window->surfaceType() == QSurface::VulkanSurface)
return new QEglFSVulkanWindow(window);
return QEglFSDeviceIntegration::createWindow(window);
}
QPlatformVulkanInstance *QEglFSVivIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
{
return new QEglFSVulkanInstance(instance);
}
#endif // vulkan
QT_END_NAMESPACE

View File

@ -53,6 +53,12 @@ public:
void destroyNativeWindow(EGLNativeWindowType window) override;
EGLNativeDisplayType platformDisplay() const override;
// Vulkan support with VK_KHR_display
#if QT_CONFIG(vulkan)
QEglFSWindow *createWindow(QWindow *window) const override;
QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) override;
#endif
private:
QSize mScreenSize;
EGLNativeDisplayType mNativeDisplay;

View File

@ -20,6 +20,9 @@ qtHaveModule(input_support-private): \
qtHaveModule(platformcompositor_support-private): \
QT += platformcompositor_support-private
qtConfig(vulkan): \
QT += vulkan_support-private
# Avoid X11 header collision, use generic EGL native types
DEFINES += QT_EGL_NO_X11