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:
parent
dd23313d66
commit
e0e7c42a19
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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); }
|
||||
|
||||
|
280
src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance.cpp
Normal file
280
src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance.cpp
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user