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)
{