x11: Use global share context

This is needed to share window thumbnails between kwin's scene graph and
qtquick.
This commit is contained in:
Vlad Zahorodnii 2021-06-03 09:24:52 +03:00
parent 8ed364337b
commit 172c541cad
6 changed files with 60 additions and 30 deletions

View file

@ -29,8 +29,6 @@
namespace KWin namespace KWin
{ {
static std::unique_ptr<QOpenGLContext> s_shareContext;
class Q_DECL_HIDDEN EffectQuickView::Private class Q_DECL_HIDDEN EffectQuickView::Private
{ {
public: public:
@ -88,7 +86,7 @@ EffectQuickView::EffectQuickView(QObject *parent, ExportMode exportMode)
format.setStencilBufferSize(8); format.setStencilBufferSize(8);
d->m_glcontext.reset(new QOpenGLContext); d->m_glcontext.reset(new QOpenGLContext);
d->m_glcontext->setShareContext(s_shareContext.get()); d->m_glcontext->setShareContext(QOpenGLContext::globalShareContext());
d->m_glcontext->setFormat(format); d->m_glcontext->setFormat(format);
d->m_glcontext->create(); d->m_glcontext->create();
@ -103,11 +101,6 @@ EffectQuickView::EffectQuickView(QObject *parent, ExportMode exportMode)
if (!d->m_glcontext->shareContext()) { if (!d->m_glcontext->shareContext()) {
qCDebug(LIBKWINEFFECTS) << "Failed to create a shared context, falling back to raster rendering"; qCDebug(LIBKWINEFFECTS) << "Failed to create a shared context, falling back to raster rendering";
qCDebug(LIBKWINEFFECTS) << "Extra debug:";
qCDebug(LIBKWINEFFECTS) << "our context:" << d->m_glcontext.data();
qCDebug(LIBKWINEFFECTS) << "share context:" << s_shareContext.get();
// still render via GL, but blit for presentation // still render via GL, but blit for presentation
d->m_useBlit = true; d->m_useBlit = true;
} }
@ -238,11 +231,6 @@ void EffectQuickView::forwardKeyEvent(QKeyEvent *keyEvent)
QCoreApplication::sendEvent(d->m_view, keyEvent); QCoreApplication::sendEvent(d->m_view, keyEvent);
} }
void EffectQuickView::setShareContext(std::unique_ptr<QOpenGLContext> context)
{
s_shareContext = std::move(context);
}
QRect EffectQuickView::geometry() const QRect EffectQuickView::geometry() const
{ {
return d->m_view->geometry(); return d->m_view->geometry();

View file

@ -21,7 +21,6 @@
class QKeyEvent; class QKeyEvent;
class QMouseEvent; class QMouseEvent;
class QOpenGLContext;
class QMouseEvent; class QMouseEvent;
class QKeyEvent; class QKeyEvent;
@ -49,8 +48,6 @@ class KWINEFFECTS_EXPORT EffectQuickView : public QObject
Q_OBJECT Q_OBJECT
public: public:
static void setShareContext(std::unique_ptr<QOpenGLContext> context);
enum class ExportMode { enum class ExportMode {
/** The contents will be available as a texture in the shared contexts. Image will be blank*/ /** The contents will be available as a texture in the shared contexts. Image will be blank*/
Texture, Texture,

View file

@ -417,6 +417,15 @@ int main(int argc, char * argv[])
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
// KSMServer talks to us directly on DBus. // KSMServer talks to us directly on DBus.
QCoreApplication::setAttribute(Qt::AA_DisableSessionManager); QCoreApplication::setAttribute(Qt::AA_DisableSessionManager);
// For sharing thumbnails between our scene graph and qtquick.
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
// shared opengl contexts must have the same reset notification policy
format.setOptions(QSurfaceFormat::ResetNotification);
// disables vsync for any QtQuick windows we create (BUG 406180)
format.setSwapInterval(0);
QSurfaceFormat::setDefaultFormat(format);
KWin::ApplicationX11 a(argc, argv); KWin::ApplicationX11 a(argc, argv);
a.setupTranslator(); a.setupTranslator();
@ -424,11 +433,6 @@ int main(int argc, char * argv[])
KWin::Application::createAboutData(); KWin::Application::createAboutData();
KQuickAddons::QtQuickSettings::init(); KQuickAddons::QtQuickSettings::init();
// disables vsync for any QtQuick windows we create (BUG 406180)
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
format.setSwapInterval(0);
QSurfaceFormat::setDefaultFormat(format);
QCommandLineOption replaceOption(QStringLiteral("replace"), i18n("Replace already-running ICCCM2.0-compliant window manager")); QCommandLineOption replaceOption(QStringLiteral("replace"), i18n("Replace already-running ICCCM2.0-compliant window manager"));
QCommandLineParser parser; QCommandLineParser parser;

View file

@ -6,6 +6,7 @@
*/ */
#include "eglbackend.h" #include "eglbackend.h"
#include "logging.h"
#include "options.h" #include "options.h"
#include "overlaywindow.h" #include "overlaywindow.h"
#include "platform.h" #include "platform.h"
@ -16,6 +17,9 @@
#include "surfaceitem_x11.h" #include "surfaceitem_x11.h"
#include "x11_platform.h" #include "x11_platform.h"
#include <QOpenGLContext>
#include <QtPlatformHeaders/QEGLNativeContext>
namespace KWin namespace KWin
{ {
@ -48,6 +52,30 @@ PlatformSurfaceTexture *EglBackend::createPlatformSurfaceTextureX11(SurfacePixma
return new EglSurfaceTextureX11(this, texture); return new EglSurfaceTextureX11(this, texture);
} }
void EglBackend::init()
{
QOpenGLContext *qtShareContext = QOpenGLContext::globalShareContext();
EGLContext shareContext = EGL_NO_CONTEXT;
if (qtShareContext) {
qDebug(KWIN_X11STANDALONE) << "Global share context format:" << qtShareContext->format();
const QVariant nativeHandle = qtShareContext->nativeHandle();
if (!nativeHandle.canConvert<QEGLNativeContext>()) {
setFailed(QStringLiteral("Invalid QOpenGLContext::globalShareContext()"));
return;
} else {
QEGLNativeContext handle = qvariant_cast<QEGLNativeContext>(nativeHandle);
shareContext = handle.context();
}
}
if (shareContext == EGL_NO_CONTEXT) {
setFailed(QStringLiteral("QOpenGLContext::globalShareContext() is required"));
return;
}
kwinApp()->platform()->setSceneEglGlobalShareContext(shareContext);
EglOnXBackend::init();
}
void EglBackend::screenGeometryChanged(const QSize &size) void EglBackend::screenGeometryChanged(const QSize &size)
{ {
Q_UNUSED(size) Q_UNUSED(size)

View file

@ -27,6 +27,8 @@ public:
EglBackend(Display *display, X11StandalonePlatform *platform); EglBackend(Display *display, X11StandalonePlatform *platform);
~EglBackend() override; ~EglBackend() override;
void init() override;
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *texture) override; PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *texture) override;
QRegion beginFrame(int screenId) override; QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;

View file

@ -129,7 +129,6 @@ GlxBackend::~GlxBackend()
// do cleanup after initBuffer() // do cleanup after initBuffer()
cleanupGL(); cleanupGL();
doneCurrent(); doneCurrent();
EffectQuickView::setShareContext(nullptr);
if (ctx) if (ctx)
glXDestroyContext(display(), ctx); glXDestroyContext(display(), ctx);
@ -311,6 +310,24 @@ bool GlxBackend::initRenderingContext()
{ {
const bool direct = true; const bool direct = true;
QOpenGLContext *qtGlobalShareContext = QOpenGLContext::globalShareContext();
GLXContext globalShareContext = nullptr;
if (qtGlobalShareContext) {
qDebug(KWIN_X11STANDALONE) << "Global share context format:" << qtGlobalShareContext->format();
const QVariant nativeHandle = qtGlobalShareContext->nativeHandle();
if (!nativeHandle.canConvert<QGLXNativeContext>()) {
qCDebug(KWIN_X11STANDALONE) << "Invalid QOpenGLContext::globalShareContext()";
return false;
} else {
QGLXNativeContext handle = qvariant_cast<QGLXNativeContext>(nativeHandle);
globalShareContext = handle.context();
}
}
if (!globalShareContext) {
qCWarning(KWIN_X11STANDALONE) << "QOpenGLContext::globalShareContext() is required";
return false;
}
// Use glXCreateContextAttribsARB() when it's available // Use glXCreateContextAttribsARB() when it's available
if (hasExtension(QByteArrayLiteral("GLX_ARB_create_context"))) { if (hasExtension(QByteArrayLiteral("GLX_ARB_create_context"))) {
const bool have_robustness = hasExtension(QByteArrayLiteral("GLX_ARB_create_context_robustness")); const bool have_robustness = hasExtension(QByteArrayLiteral("GLX_ARB_create_context_robustness"));
@ -352,7 +369,7 @@ bool GlxBackend::initRenderingContext()
} }
for (auto it = candidates.begin(); it != candidates.end(); it++) { for (auto it = candidates.begin(); it != candidates.end(); it++) {
const auto attribs = it->build(); const auto attribs = it->build();
ctx = glXCreateContextAttribsARB(display(), fbconfig, nullptr, true, attribs.data()); ctx = glXCreateContextAttribsARB(display(), fbconfig, globalShareContext, true, attribs.data());
if (ctx) { if (ctx) {
qCDebug(KWIN_X11STANDALONE) << "Created GLX context with attributes:" << &(*it); qCDebug(KWIN_X11STANDALONE) << "Created GLX context with attributes:" << &(*it);
break; break;
@ -361,7 +378,7 @@ bool GlxBackend::initRenderingContext()
} }
if (!ctx) if (!ctx)
ctx = glXCreateNewContext(display(), fbconfig, GLX_RGBA_TYPE, nullptr, direct); ctx = glXCreateNewContext(display(), fbconfig, GLX_RGBA_TYPE, globalShareContext, direct);
if (!ctx) { if (!ctx) {
qCDebug(KWIN_X11STANDALONE) << "Failed to create an OpenGL context."; qCDebug(KWIN_X11STANDALONE) << "Failed to create an OpenGL context.";
@ -375,12 +392,6 @@ bool GlxBackend::initRenderingContext()
return false; return false;
} }
auto qtContext = new QOpenGLContext;
QGLXNativeContext native(ctx, display());
qtContext->setNativeHandle(QVariant::fromValue(native));
qtContext->create();
EffectQuickView::setShareContext(std::unique_ptr<QOpenGLContext>(qtContext));
return true; return true;
} }