diff --git a/abstract_egl_backend.cpp b/abstract_egl_backend.cpp index 28c557db16..2019de982a 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 *pixmap) { const auto &buffer = 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 *pixmap) { const auto &buffer = pixmap->buffer(); if (buffer.isNull()) { + const auto &fbo = pixmap->fbo(); + if (!fbo.isNull()) { + if (m_texture != 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 = fbo->texture(); + m_size = 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 b2ae051905..965abe094c 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 2cce31a40e..c46f8d1db6 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 != XCB_PIXMAP_NONE; } @@ -1004,6 +1004,12 @@ void WindowPixmap::updateBuffer() m_buffer = b; m_buffer->ref(); QObject::connect(m_buffer.data(), &BufferInterface::aboutToBeDestroyed, m_buffer.data(), &BufferInterface::unref); + } else { + // might be an internal window + const auto &fbo = toplevel()->internalFramebufferObject(); + if (!fbo.isNull()) { + m_fbo = fbo; + } } } } diff --git a/scene.h b/scene.h index 640e861c10..84740c708c 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 means 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 WindowPixmap::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 4d32c271d6..44c503d031 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 = 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 bf5bcdf00f..a62998603d 100644 --- a/shell_client.h +++ b/shell_client.h @@ -96,6 +96,8 @@ public: void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet) 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 7201b785ca..1af892a551 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -130,6 +130,7 @@ void Toplevel::copyToDeleted(Toplevel* c) opaque_region = c->opaqueRegion(); m_screen = c->m_screen; m_skipCloseAnimation = c->m_skipCloseAnimation; + m_internalFBO = 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 != fbo) { + discardWindowPixmap(); + m_internalFBO = fbo; + } + setDepth(32); +} + } // namespace #include "toplevel.moc" diff --git a/toplevel.h b/toplevel.h index dfb246f29c..c71a905df7 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 &internalFramebufferObject() const; + /** * @brief Finds the Toplevel matching the condition expressed in @p func in @p list. * @@ -495,6 +500,10 @@ private: bool m_skipCloseAnimation; quint32 m_surfaceId = 0; KWayland::Server::SurfaceInterface *m_surface = 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::surface() const return m_surface; } +inline const QSharedPointer &Toplevel::internalFramebufferObject() const +{ + return m_internalFBO; +} + template inline T *Toplevel::findInList(const QList &list, std::function func) {