diff --git a/plugins/qpa/CMakeLists.txt b/plugins/qpa/CMakeLists.txt --- a/plugins/qpa/CMakeLists.txt +++ b/plugins/qpa/CMakeLists.txt @@ -8,6 +8,7 @@ integration.cpp main.cpp nativeinterface.cpp + offscreensurface.cpp platformcursor.cpp screen.cpp sharingplatformcontext.cpp 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; }