292335beac
On Wayland, internal windows that use OpenGL are rendered into fbos, which are later handed over to kwin. In order to achieve that, our QPA creates OpenGL contexts that share resources with the scene's context. The problems start when compositing has been restarted. If user changes any compositing settings, the underlying render backend will be reinitialized and with it, the scene's context will be destroyed. Thus, we no longer can accept framebuffer objects from internal windows. This change addresses the framebuffer object sharing problem by adding a so called global share context. It persists throughout the lifetime of kwin. It can never be made current. The scene context and all contexts created in our QPA share resources with it. Therefore we can destroy the scene OpenGL context without affecting OpenGL contexts owned by internal windows, e.g. the outline visual or tabbox. It's worth noting that Qt provides a way to create a global share context. But for our purposes it's not suitable since the share context must be known when QGuiApplication attempts to instantiate a QOpenGLContext object. At that moment, the backend is not initialized and thus the EGLDisplay is not available yet. BUG: 415798
159 lines
4.1 KiB
C++
159 lines
4.1 KiB
C++
/*
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
|
SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
#include "integration.h"
|
|
#include "backingstore.h"
|
|
#include "eglplatformcontext.h"
|
|
#include "logging.h"
|
|
#include "offscreensurface.h"
|
|
#include "screen.h"
|
|
#include "window.h"
|
|
#include "../../main.h"
|
|
#include "../../platform.h"
|
|
#include "../../screens.h"
|
|
|
|
#include <QCoreApplication>
|
|
#include <QtConcurrentRun>
|
|
|
|
#include <qpa/qplatformwindow.h>
|
|
#include <qpa/qwindowsysteminterface.h>
|
|
|
|
#include <QtEventDispatcherSupport/private/qunixeventdispatcher_qpa_p.h>
|
|
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
|
|
#include <QtThemeSupport/private/qgenericunixthemes_p.h>
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
namespace QPA
|
|
{
|
|
|
|
Integration::Integration()
|
|
: QObject()
|
|
, QPlatformIntegration()
|
|
, m_fontDb(new QGenericUnixFontDatabase())
|
|
{
|
|
}
|
|
|
|
Integration::~Integration()
|
|
{
|
|
for (QPlatformScreen *platformScreen : m_screens) {
|
|
QWindowSystemInterface::handleScreenRemoved(platformScreen);
|
|
}
|
|
}
|
|
|
|
bool Integration::hasCapability(Capability cap) const
|
|
{
|
|
switch (cap) {
|
|
case ThreadedPixmaps:
|
|
return true;
|
|
case OpenGL:
|
|
return true;
|
|
case ThreadedOpenGL:
|
|
return false;
|
|
case BufferQueueingOpenGL:
|
|
return false;
|
|
case MultipleWindows:
|
|
case NonFullScreenWindows:
|
|
return true;
|
|
case RasterGLSurface:
|
|
return false;
|
|
default:
|
|
return QPlatformIntegration::hasCapability(cap);
|
|
}
|
|
}
|
|
|
|
void Integration::initialize()
|
|
{
|
|
connect(kwinApp(), &Application::screensCreated, this,
|
|
[this] {
|
|
connect(screens(), &Screens::changed, this, &Integration::initScreens);
|
|
initScreens();
|
|
}
|
|
);
|
|
QPlatformIntegration::initialize();
|
|
auto dummyScreen = new Screen(-1);
|
|
QWindowSystemInterface::handleScreenAdded(dummyScreen);
|
|
m_screens << dummyScreen;
|
|
}
|
|
|
|
QAbstractEventDispatcher *Integration::createEventDispatcher() const
|
|
{
|
|
return new QUnixEventDispatcherQPA;
|
|
}
|
|
|
|
QPlatformBackingStore *Integration::createPlatformBackingStore(QWindow *window) const
|
|
{
|
|
return new BackingStore(window);
|
|
}
|
|
|
|
QPlatformWindow *Integration::createPlatformWindow(QWindow *window) const
|
|
{
|
|
return new Window(window);
|
|
}
|
|
|
|
QPlatformOffscreenSurface *Integration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
|
|
{
|
|
return new OffscreenSurface(surface);
|
|
}
|
|
|
|
QPlatformFontDatabase *Integration::fontDatabase() const
|
|
{
|
|
return m_fontDb.data();
|
|
}
|
|
|
|
QPlatformTheme *Integration::createPlatformTheme(const QString &name) const
|
|
{
|
|
return QGenericUnixTheme::createUnixTheme(name);
|
|
}
|
|
|
|
QStringList Integration::themeNames() const
|
|
{
|
|
if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) {
|
|
return QStringList({QStringLiteral("kde")});
|
|
}
|
|
return QStringList({QLatin1String(QGenericUnixTheme::name)});
|
|
}
|
|
|
|
QPlatformOpenGLContext *Integration::createPlatformOpenGLContext(QOpenGLContext *context) const
|
|
{
|
|
if (kwinApp()->platform()->sceneEglGlobalShareContext() == EGL_NO_CONTEXT) {
|
|
qCWarning(KWIN_QPA) << "Attempting to create a QOpenGLContext before the scene is initialized";
|
|
return nullptr;
|
|
}
|
|
const EGLDisplay eglDisplay = kwinApp()->platform()->sceneEglDisplay();
|
|
if (eglDisplay != EGL_NO_DISPLAY) {
|
|
EGLPlatformContext *platformContext = new EGLPlatformContext(context, eglDisplay);
|
|
return platformContext;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void Integration::initScreens()
|
|
{
|
|
QVector<Screen*> newScreens;
|
|
newScreens.reserve(qMax(screens()->count(), 1));
|
|
for (int i = 0; i < screens()->count(); i++) {
|
|
auto screen = new Screen(i);
|
|
QWindowSystemInterface::handleScreenAdded(screen);
|
|
newScreens << screen;
|
|
}
|
|
if (newScreens.isEmpty()) {
|
|
auto dummyScreen = new Screen(-1);
|
|
QWindowSystemInterface::handleScreenAdded(dummyScreen);
|
|
newScreens << dummyScreen;
|
|
}
|
|
while (!m_screens.isEmpty()) {
|
|
QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
|
|
}
|
|
m_screens = newScreens;
|
|
}
|
|
|
|
}
|
|
}
|