diff --git a/plugins/qpa/CMakeLists.txt b/plugins/qpa/CMakeLists.txt
--- a/plugins/qpa/CMakeLists.txt
+++ b/plugins/qpa/CMakeLists.txt
@@ -4,9 +4,11 @@
set(QPA_SOURCES
abstractplatformcontext.cpp
backingstore.cpp
+ eglhelpers.cpp
integration.cpp
main.cpp
nativeinterface.cpp
+ offscreensurface.cpp
platformcursor.cpp
screen.cpp
sharingplatformcontext.cpp
diff --git a/plugins/qpa/abstractplatformcontext.cpp b/plugins/qpa/abstractplatformcontext.cpp
--- a/plugins/qpa/abstractplatformcontext.cpp
+++ b/plugins/qpa/abstractplatformcontext.cpp
@@ -18,88 +18,25 @@
along with this program. If not, see .
*********************************************************************/
#include "abstractplatformcontext.h"
-#include "integration.h"
#include "egl_context_attribute_builder.h"
+#include "eglhelpers.h"
+
#include
+#include
+
#include
namespace KWin
{
namespace QPA
{
-static bool isOpenGLES()
-{
- if (qstrcmp(qgetenv("KWIN_COMPOSE"), "O2ES") == 0) {
- return true;
- }
- return QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES;
-}
-
-static EGLConfig configFromGLFormat(EGLDisplay dpy, const QSurfaceFormat &format)
-{
-#define SIZE( __buffer__ ) format.__buffer__##BufferSize() > 0 ? format.__buffer__##BufferSize() : 0
- // not setting samples as QtQuick doesn't need it
- const EGLint config_attribs[] = {
- EGL_SURFACE_TYPE, 0,
- EGL_RED_SIZE, SIZE(red),
- EGL_GREEN_SIZE, SIZE(green),
- EGL_BLUE_SIZE, SIZE(blue),
- EGL_ALPHA_SIZE, SIZE(alpha),
- EGL_DEPTH_SIZE, SIZE(depth),
- EGL_STENCIL_SIZE, SIZE(stencil),
- EGL_RENDERABLE_TYPE, isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
- EGL_NONE,
- };
- qCDebug(KWIN_QPA) << "Trying to find a format with: rgba/depth/stencil" << (SIZE(red)) << (SIZE(green)) <<( SIZE(blue)) << (SIZE(alpha)) << (SIZE(depth)) << (SIZE(stencil));
-#undef SIZE
-
- EGLint count;
- EGLConfig configs[1024];
- if (eglChooseConfig(dpy, config_attribs, configs, 1, &count) == EGL_FALSE) {
- qCWarning(KWIN_QPA) << "eglChooseConfig failed";
- return 0;
- }
- if (count != 1) {
- qCWarning(KWIN_QPA) << "eglChooseConfig did not return any configs";
- return 0;
- }
- return configs[0];
-}
-
-static QSurfaceFormat formatFromConfig(EGLDisplay dpy, EGLConfig config)
-{
- QSurfaceFormat format;
- EGLint value = 0;
-#define HELPER(__egl__, __qt__) \
- eglGetConfigAttrib(dpy, config, EGL_##__egl__, &value); \
- format.set##__qt__(value); \
- value = 0;
-
-#define BUFFER_HELPER(__eglColor__, __color__) \
- HELPER(__eglColor__##_SIZE, __color__##BufferSize)
-
- BUFFER_HELPER(RED, Red)
- BUFFER_HELPER(GREEN, Green)
- BUFFER_HELPER(BLUE, Blue)
- BUFFER_HELPER(ALPHA, Alpha)
- BUFFER_HELPER(STENCIL, Stencil)
- BUFFER_HELPER(DEPTH, Depth)
-#undef BUFFER_HELPER
- HELPER(SAMPLES, Samples)
-#undef HELPER
- format.setRenderableType(isOpenGLES() ? QSurfaceFormat::OpenGLES : QSurfaceFormat::OpenGL);
- format.setStereo(false);
-
- return format;
-}
-
AbstractPlatformContext::AbstractPlatformContext(QOpenGLContext *context, EGLDisplay display, EGLConfig config)
: QPlatformOpenGLContext()
, m_eglDisplay(display)
- , m_config(config ? config :configFromGLFormat(m_eglDisplay, context->format()))
+ , m_config(config ? config : configFromFormat(m_eglDisplay, context->format()))
, m_format(formatFromConfig(m_eglDisplay, m_config))
{
}
diff --git a/plugins/qpa/eglhelpers.h b/plugins/qpa/eglhelpers.h
new file mode 100644
--- /dev/null
+++ b/plugins/qpa/eglhelpers.h
@@ -0,0 +1,40 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2019 Vlad Zagorodniy
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+#pragma once
+
+#define MESA_EGL_NO_X11_HEADERS
+#include
+#include "fixqopengl.h"
+
+#include
+
+namespace KWin
+{
+namespace QPA
+{
+
+bool isOpenGLES();
+
+EGLConfig configFromFormat(EGLDisplay display, const QSurfaceFormat &surfaceFormat, EGLint surfaceType = 0);
+QSurfaceFormat formatFromConfig(EGLDisplay display, EGLConfig config);
+
+} // namespace QPA
+} // namespace KWin
diff --git a/plugins/qpa/eglhelpers.cpp b/plugins/qpa/eglhelpers.cpp
new file mode 100644
--- /dev/null
+++ b/plugins/qpa/eglhelpers.cpp
@@ -0,0 +1,116 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Flöser
+Copyright (C) 2019 Vlad Zagorodniy
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+#include "eglhelpers.h"
+
+#include
+
+#include
+
+namespace KWin
+{
+namespace QPA
+{
+
+bool isOpenGLES()
+{
+ if (qstrcmp(qgetenv("KWIN_COMPOSE"), "O2ES") == 0) {
+ return true;
+ }
+
+ return QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES;
+}
+
+EGLConfig configFromFormat(EGLDisplay display, const QSurfaceFormat &surfaceFormat, EGLint surfaceType)
+{
+ // qMax as these values are initialized to -1 by default.
+ const EGLint redSize = qMax(surfaceFormat.redBufferSize(), 0);
+ const EGLint greenSize = qMax(surfaceFormat.greenBufferSize(), 0);
+ const EGLint blueSize = qMax(surfaceFormat.blueBufferSize(), 0);
+ const EGLint alphaSize = qMax(surfaceFormat.alphaBufferSize(), 0);
+ const EGLint depthSize = qMax(surfaceFormat.depthBufferSize(), 0);
+ const EGLint stencilSize = qMax(surfaceFormat.stencilBufferSize(), 0);
+
+ const EGLint renderableType = isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT;
+
+ // Not setting samples as QtQuick doesn't need it.
+ const QVector attributes {
+ EGL_SURFACE_TYPE, surfaceType,
+ EGL_RED_SIZE, redSize,
+ EGL_GREEN_SIZE, greenSize,
+ EGL_BLUE_SIZE, blueSize,
+ EGL_ALPHA_SIZE, alphaSize,
+ EGL_DEPTH_SIZE, depthSize,
+ EGL_STENCIL_SIZE, stencilSize,
+ EGL_RENDERABLE_TYPE, renderableType,
+ EGL_NONE
+ };
+
+ EGLint configCount;
+ EGLConfig configs[1024];
+ if (!eglChooseConfig(display, attributes.data(), configs, 1, &configCount)) {
+ // FIXME: Don't bail out yet, we should try to find the most suitable config.
+ qCWarning(KWIN_QPA, "eglChooseConfig failed: %x", eglGetError());
+ return EGL_NO_CONFIG_KHR;
+ }
+
+ if (configCount != 1) {
+ qCWarning(KWIN_QPA) << "eglChooseConfig did not return any configs";
+ return EGL_NO_CONFIG_KHR;
+ }
+
+ return configs[0];
+}
+
+QSurfaceFormat formatFromConfig(EGLDisplay display, EGLConfig config)
+{
+ int redSize = 0;
+ int blueSize = 0;
+ int greenSize = 0;
+ int alphaSize = 0;
+ int stencilSize = 0;
+ int depthSize = 0;
+ int sampleCount = 0;
+
+ eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize);
+ eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize);
+ eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize);
+ eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaSize);
+ eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize);
+ eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depthSize);
+ eglGetConfigAttrib(display, config, EGL_SAMPLES, &sampleCount);
+
+ QSurfaceFormat format;
+ format.setRedBufferSize(redSize);
+ format.setGreenBufferSize(greenSize);
+ format.setBlueBufferSize(blueSize);
+ format.setAlphaBufferSize(alphaSize);
+ format.setStencilBufferSize(stencilSize);
+ format.setDepthBufferSize(depthSize);
+ format.setSamples(sampleCount);
+ format.setRenderableType(isOpenGLES() ? QSurfaceFormat::OpenGLES : QSurfaceFormat::OpenGL);
+ format.setStereo(false);
+
+ return format;
+}
+
+} // namespace QPA
+} // namespace KWin
diff --git a/plugins/qpa/integration.h b/plugins/qpa/integration.h
--- a/plugins/qpa/integration.h
+++ b/plugins/qpa/integration.h
@@ -53,6 +53,7 @@
bool hasCapability(Capability cap) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
QAbstractEventDispatcher *createEventDispatcher() const override;
QPlatformFontDatabase *fontDatabase() const override;
diff --git a/plugins/qpa/integration.cpp b/plugins/qpa/integration.cpp
--- a/plugins/qpa/integration.cpp
+++ b/plugins/qpa/integration.cpp
@@ -22,6 +22,7 @@
#include "platform.h"
#include "backingstore.h"
#include "nativeinterface.h"
+#include "offscreensurface.h"
#include "screen.h"
#include "sharingplatformcontext.h"
#include "window.h"
@@ -160,6 +161,11 @@
}
}
+QPlatformOffscreenSurface *Integration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
+{
+ return new OffscreenSurface(surface);
+}
+
QPlatformFontDatabase *Integration::fontDatabase() const
{
return m_fontDb;
diff --git a/plugins/qpa/offscreensurface.h b/plugins/qpa/offscreensurface.h
new file mode 100644
--- /dev/null
+++ b/plugins/qpa/offscreensurface.h
@@ -0,0 +1,53 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2019 Vlad Zagorodniy
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+#pragma once
+
+#define MESA_EGL_NO_X11_HEADERS
+#include
+#include "fixqopengl.h"
+
+#include
+
+namespace KWin
+{
+namespace QPA
+{
+
+class OffscreenSurface : public QPlatformOffscreenSurface
+{
+public:
+ explicit OffscreenSurface(QOffscreenSurface *surface);
+ ~OffscreenSurface() override;
+
+ QSurfaceFormat format() const override;
+ bool isValid() const override;
+
+ EGLSurface nativeHandle() const;
+
+private:
+ QSurfaceFormat m_format;
+
+ EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
+ EGLSurface m_surface = EGL_NO_SURFACE;
+};
+
+} // namespace QPA
+} // namespace KWin
diff --git a/plugins/qpa/offscreensurface.cpp b/plugins/qpa/offscreensurface.cpp
new file mode 100644
--- /dev/null
+++ b/plugins/qpa/offscreensurface.cpp
@@ -0,0 +1,82 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2019 Vlad Zagorodniy
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+#include "offscreensurface.h"
+#include "eglhelpers.h"
+#include "main.h"
+#include "platform.h"
+
+#include
+
+namespace KWin
+{
+namespace QPA
+{
+
+OffscreenSurface::OffscreenSurface(QOffscreenSurface *surface)
+ : QPlatformOffscreenSurface(surface)
+ , m_eglDisplay(kwinApp()->platform()->sceneEglDisplay())
+{
+ const QSize size = surface->size();
+
+ EGLConfig config = configFromFormat(m_eglDisplay, surface->requestedFormat(), EGL_PBUFFER_BIT);
+ if (config == EGL_NO_CONFIG_KHR) {
+ return;
+ }
+
+ const EGLint attributes[] = {
+ EGL_WIDTH, size.width(),
+ EGL_HEIGHT, size.height(),
+ EGL_NONE
+ };
+
+ m_surface = eglCreatePbufferSurface(m_eglDisplay, config, attributes);
+ if (m_surface == EGL_NO_SURFACE) {
+ return;
+ }
+
+ // Requested and actual surface format might be different.
+ m_format = formatFromConfig(m_eglDisplay, config);
+}
+
+OffscreenSurface::~OffscreenSurface()
+{
+ if (m_surface != EGL_NO_SURFACE) {
+ eglDestroySurface(m_eglDisplay, m_surface);
+ }
+}
+
+QSurfaceFormat OffscreenSurface::format() const
+{
+ return m_format;
+}
+
+bool OffscreenSurface::isValid() const
+{
+ return m_surface != EGL_NO_SURFACE;
+}
+
+EGLSurface OffscreenSurface::nativeHandle() const
+{
+ return m_surface;
+}
+
+} // namespace QPA
+} // namespace KWin
diff --git a/plugins/qpa/sharingplatformcontext.cpp b/plugins/qpa/sharingplatformcontext.cpp
--- a/plugins/qpa/sharingplatformcontext.cpp
+++ b/plugins/qpa/sharingplatformcontext.cpp
@@ -19,6 +19,7 @@
*********************************************************************/
#include "sharingplatformcontext.h"
#include "integration.h"
+#include "offscreensurface.h"
#include "window.h"
#include "../../platform.h"
#include "../../wayland_server.h"
@@ -48,22 +49,30 @@
bool SharingPlatformContext::makeCurrent(QPlatformSurface *surface)
{
- Window *window = static_cast(surface);
+ EGLSurface eglSurface;
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ eglSurface = m_surface;
+ } else {
+ eglSurface = static_cast(surface)->nativeHandle();
+ }
- // QOpenGLContext::makeCurrent in Qt5.12 calls platfrom->setContext before setCurrentContext
- // but binding the content FBO looks up the format from the current context, so we need // to make sure sure Qt knows what the correct one is already
- QOpenGLContextPrivate::setCurrentContext(context());
- if (eglMakeCurrent(eglDisplay(), m_surface, m_surface, eglContext())) {
- window->bindContentFBO();
- return true;
+ const bool ok = eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext());
+ if (!ok) {
+ qCWarning(KWIN_QPA, "eglMakeCurrent failed: %x", eglGetError());
+ return false;
}
- qCWarning(KWIN_QPA) << "Failed to make context current";
- EGLint error = eglGetError();
- if (error != EGL_SUCCESS) {
- qCWarning(KWIN_QPA) << "EGL error code: " << error;
+
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ // QOpenGLContextPrivate::setCurrentContext will be called after this
+ // method returns, but that's too late, as we need a current context in
+ // order to bind the content framebuffer object.
+ QOpenGLContextPrivate::setCurrentContext(context());
+
+ Window *window = static_cast(surface);
+ window->bindContentFBO();
}
- return false;
+ return true;
}
bool SharingPlatformContext::isSharing() const
@@ -73,16 +82,18 @@
void SharingPlatformContext::swapBuffers(QPlatformSurface *surface)
{
- Window *window = static_cast(surface);
- auto c = window->shellClient();
- if (!c) {
- qCDebug(KWIN_QPA) << "SwapBuffers called but there is no ShellClient";
- return;
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ Window *window = static_cast(surface);
+ auto c = window->shellClient();
+ if (!c) {
+ qCDebug(KWIN_QPA) << "SwapBuffers called but there is no ShellClient";
+ return;
+ }
+ context()->makeCurrent(surface->surface());
+ glFlush();
+ c->setInternalFramebufferObject(window->swapFBO());
+ window->bindContentFBO();
}
- context()->makeCurrent(surface->surface());
- glFlush();
- c->setInternalFramebufferObject(window->swapFBO());
- window->bindContentFBO();
}
GLuint SharingPlatformContext::defaultFramebufferObject(QPlatformSurface *surface) const
@@ -93,7 +104,7 @@
return fbo->handle();
}
}
- qCDebug(KWIN_QPA) << "No default framebuffer object for internal window";
+
return 0;
}