From kde-commits Tue Aug 25 12:41:15 2015 From: =?utf-8?q?Martin_Gr=C3=A4=C3=9Flin?= Date: Tue, 25 Aug 2015 12:41:15 +0000 To: kde-commits Subject: [kwin] /: Composite windows from a QOpenGLFramebufferObject Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=144050649303062 Git commit c56bbc0ddfd6613ac8b357a0e284801bb7532c96 by Martin Gr=C3=A4=C3= =9Flin. Committed on 25/08/2015 at 12:33. Pushed by graesslin into branch 'master'. Composite windows from a QOpenGLFramebufferObject This change introduces a mechanism for internal windows to be rendered to a QOpenGLFramebufferObject to be composited using the texture bound to the FBO. This is useful for in-process rendering (e.g. QtQuick) and at the same time bypassing the windowing system. The OpenGL context of the QOpenGLFramebufferObject needs to be sharing with the compositing OpenGL context. M +25 -0 abstract_egl_backend.cpp M +3 -0 abstract_egl_backend.h M +8 -2 scene.cpp M +10 -0 scene.h M +14 -0 shell_client.cpp M +2 -0 shell_client.h M +10 -0 toplevel.cpp M +14 -0 toplevel.h http://commits.kde.org/kwin/c56bbc0ddfd6613ac8b357a0e284801bb7532c96 diff --git a/abstract_egl_backend.cpp b/abstract_egl_backend.cpp index 28c557d..2019de9 100644 --- a/abstract_egl_backend.cpp +++ b/abstract_egl_backend.cpp @@ -26,6 +26,7 @@ along with this program. If not, see . #include // Qt #include +#include = namespace KWin { @@ -201,6 +202,9 @@ bool AbstractEglTexture::loadTexture(WindowPixmap *pixm= ap) { const auto &buffer =3D pixmap->buffer(); if (buffer.isNull()) { + if (updateFromFBO(pixmap->fbo())) { + return true; + } // try X11 loading return loadTexture(pixmap->pixmap(), pixmap->toplevel()->size()); } @@ -246,6 +250,13 @@ void AbstractEglTexture::updateTexture(WindowPixmap *p= ixmap) { const auto &buffer =3D pixmap->buffer(); if (buffer.isNull()) { + const auto &fbo =3D pixmap->fbo(); + if (!fbo.isNull()) { + if (m_texture !=3D fbo->texture()) { + updateFromFBO(fbo); + } + return; + } return; } if (!buffer->shmBuffer()) { @@ -393,5 +404,19 @@ EGLImageKHR AbstractEglTexture::attach(const QPointer<= KWayland::Server::BufferI return image; } = +bool AbstractEglTexture::updateFromFBO(const QSharedPointer &fbo) +{ + if (fbo.isNull()) { + return false; + } + m_texture =3D fbo->texture(); + m_size =3D fbo->size(); + q->setWrapMode(GL_CLAMP_TO_EDGE); + q->setFilter(GL_LINEAR); + q->setYInverted(false); + updateMatrix(); + return true; +} + } = diff --git a/abstract_egl_backend.h b/abstract_egl_backend.h index b2ae051..965abe0 100644 --- a/abstract_egl_backend.h +++ b/abstract_egl_backend.h @@ -21,6 +21,8 @@ along with this program. If not, see . #define KWIN_ABSTRACT_EGL_BACKEND_H #include "scene_opengl.h" = +class QOpenGLFramebufferObject; + namespace KWin { = @@ -94,6 +96,7 @@ private: bool loadShmTexture(const QPointer = &buffer); bool loadEglTexture(const QPointer = &buffer); EGLImageKHR attach(const QPointer &= buffer); + bool updateFromFBO(const QSharedPointer &fbo= ); SceneOpenGL::Texture *q; AbstractEglBackend *m_backend; EGLImageKHR m_image; diff --git a/scene.cpp b/scene.cpp index 2cce31a..c46f8d1 100644 --- a/scene.cpp +++ b/scene.cpp @@ -950,7 +950,7 @@ void WindowPixmap::create() if (kwinApp()->shouldUseWaylandForCompositing()) { // use Buffer updateBuffer(); - if (m_buffer) { + if (m_buffer || !m_fbo.isNull()) { m_window->unreferencePreviousPixmap(); } return; @@ -987,7 +987,7 @@ void WindowPixmap::create() bool WindowPixmap::isValid() const { if (kwinApp()->shouldUseWaylandForCompositing()) { - return !m_buffer.isNull(); + return !m_buffer.isNull() || !m_fbo.isNull(); } return m_pixmap !=3D XCB_PIXMAP_NONE; } @@ -1004,6 +1004,12 @@ void WindowPixmap::updateBuffer() m_buffer =3D b; m_buffer->ref(); QObject::connect(m_buffer.data(), &BufferInterface::aboutToBeD= estroyed, m_buffer.data(), &BufferInterface::unref); + } else { + // might be an internal window + const auto &fbo =3D toplevel()->internalFramebufferObject(); + if (!fbo.isNull()) { + m_fbo =3D fbo; + } } } } diff --git a/scene.h b/scene.h index 640e861..84740c7 100644 --- a/scene.h +++ b/scene.h @@ -27,6 +27,8 @@ along with this program. If not, see . = #include = +class QOpenGLFramebufferObject; + namespace KWayland { namespace Server @@ -355,6 +357,7 @@ public: * @return The Wayland BufferInterface for this WindowPixmap. **/ QPointer buffer() const; + const QSharedPointer &fbo() const; /** * @brief Whether this WindowPixmap is considered as discarded. This m= eans the window has changed in a way that a new * WindowPixmap should have been created already. @@ -405,6 +408,7 @@ private: bool m_discarded; QRect m_contentsRect; QPointer m_buffer; + QSharedPointer m_fbo; }; = class Scene::EffectFrame @@ -514,6 +518,12 @@ QPointer WindowPixm= ap::buffer() const return m_buffer; } = +inline +const QSharedPointer &WindowPixmap::fbo() const +{ + return m_fbo; +} + template inline T* Scene::Window::windowPixmap() diff --git a/shell_client.cpp b/shell_client.cpp index 4d32c27..44c503d 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -36,6 +36,7 @@ along with this program. If not, see . = #include = +#include #include = using namespace KWayland::Server; @@ -229,6 +230,19 @@ void ShellClient::addDamage(const QRegion &damage) Toplevel::addDamage(damage); } = +void ShellClient::setInternalFramebufferObject(const QSharedPointer &fbo) +{ + if (fbo.isNull()) { + unmap(); + return; + } + markAsMapped(); + m_clientSize =3D fbo->size(); + setGeometry(QRect(geom.topLeft(), m_clientSize)); + Toplevel::setInternalFramebufferObject(fbo); + Toplevel::addDamage(QRegion(0, 0, width(), height())); +} + void ShellClient::markAsMapped() { if (!m_unmapped) { diff --git a/shell_client.h b/shell_client.h index bf5bcdf..a629986 100644 --- a/shell_client.h +++ b/shell_client.h @@ -96,6 +96,8 @@ public: void resizeWithChecks(int w, int h, ForceGeometry_t force =3D NormalGe= ometrySet) override; bool hasStrut() const override; = + void setInternalFramebufferObject(const QSharedPointer &fbo) override; + quint32 windowId() const { return m_windowId; } diff --git a/toplevel.cpp b/toplevel.cpp index 7201b78..1af892a 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -130,6 +130,7 @@ void Toplevel::copyToDeleted(Toplevel* c) opaque_region =3D c->opaqueRegion(); m_screen =3D c->m_screen; m_skipCloseAnimation =3D c->m_skipCloseAnimation; + m_internalFBO =3D c->m_internalFBO; } = // before being deleted, remove references to everything that's now @@ -507,6 +508,15 @@ QRegion Toplevel::inputShape() const } } = +void Toplevel::setInternalFramebufferObject(const QSharedPointer &fbo) +{ + if (m_internalFBO !=3D fbo) { + discardWindowPixmap(); + m_internalFBO =3D fbo; + } + setDepth(32); +} + } // namespace = #include "toplevel.moc" diff --git a/toplevel.h b/toplevel.h index dfb246f..c71a905 100644 --- a/toplevel.h +++ b/toplevel.h @@ -41,6 +41,8 @@ along with this program. If not, see . // c++ #include = +class QOpenGLFramebufferObject; + namespace KWayland { namespace Server @@ -356,6 +358,9 @@ public: KWayland::Server::SurfaceInterface *surface() const; void setSurface(KWayland::Server::SurfaceInterface *surface); = + virtual void setInternalFramebufferObject(const QSharedPointer &fbo); + const QSharedPointer &internalFramebufferObj= ect() const; + /** * @brief Finds the Toplevel matching the condition expressed in @p fu= nc in @p list. * @@ -495,6 +500,10 @@ private: bool m_skipCloseAnimation; quint32 m_surfaceId =3D 0; KWayland::Server::SurfaceInterface *m_surface =3D nullptr; + /** + * An FBO object KWin internal windows might render to. + **/ + QSharedPointer m_internalFBO; // when adding new data members, check also copyToDeleted() }; = @@ -731,6 +740,11 @@ inline KWayland::Server::SurfaceInterface *Toplevel::s= urface() const return m_surface; } = +inline const QSharedPointer &Toplevel::internalF= ramebufferObject() const +{ + return m_internalFBO; +} + template inline T *Toplevel::findInList(const QList &list, std::function func) {