[wayland] Support creating Texture from Wayland shm buffer
EglWaylandBackend gains support for creating textures from a BufferInterface. At the same time it loses the possibility to use the Xcb shm extension to load the texture. That is Xwayland is required. In order to support it in a better way the WindowPixmap is passed to the Texture for loading and updating. Which is then passed to the backend specific implementation.icc-effect-5.14.5
parent
19d90e4e0e
commit
a0b2a938aa
|
@ -24,10 +24,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "options.h"
|
||||
#include "wayland_backend.h"
|
||||
#include <KWayland/Client/surface.h>
|
||||
#include "xcbutils.h"
|
||||
// kwin libs
|
||||
#include <kwinglplatform.h>
|
||||
// KDE
|
||||
#include <KWayland/Server/buffer_interface.h>
|
||||
// Qt
|
||||
#include <QOpenGLContext>
|
||||
|
||||
|
@ -355,14 +355,6 @@ void EglWaylandBackend::doneCurrent()
|
|||
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
Xcb::Shm *EglWaylandBackend::shm()
|
||||
{
|
||||
if (m_shm.isNull()) {
|
||||
m_shm.reset(new Xcb::Shm);
|
||||
}
|
||||
return m_shm.data();
|
||||
}
|
||||
|
||||
void EglWaylandBackend::overlaySizeChanged(const QSize &size)
|
||||
{
|
||||
wl_egl_window_resize(m_overlay, size.width(), size.height(), 0, 0);
|
||||
|
@ -381,7 +373,6 @@ EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGL::Texture *texture, KWin::
|
|||
: SceneOpenGL::TexturePrivate()
|
||||
, q(texture)
|
||||
, m_backend(backend)
|
||||
, m_referencedPixmap(XCB_PIXMAP_NONE)
|
||||
{
|
||||
m_target = GL_TEXTURE_2D;
|
||||
}
|
||||
|
@ -395,42 +386,42 @@ OpenGLBackend *EglWaylandTexture::backend()
|
|||
return m_backend;
|
||||
}
|
||||
|
||||
bool EglWaylandTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual)
|
||||
bool EglWaylandTexture::loadTexture(WindowPixmap *pixmap)
|
||||
{
|
||||
Q_UNUSED(visual)
|
||||
|
||||
// HACK: egl wayland platform doesn't support texture from X11 pixmap through the KHR_image_pixmap
|
||||
// extension. To circumvent this problem we copy the pixmap content into a SHM image and from there
|
||||
// to the OpenGL texture. This is a temporary solution. In future we won't need to get the content
|
||||
// from X11 pixmaps. That's what we have XWayland for to get the content into a nice Wayland buffer.
|
||||
if (pix == XCB_PIXMAP_NONE)
|
||||
return false;
|
||||
|
||||
m_referencedPixmap = pix;
|
||||
|
||||
Xcb::Shm *shm = m_backend->shm();
|
||||
if (!shm->isValid()) {
|
||||
if (GLPlatform::instance()->isGLES()) {
|
||||
// FIXME
|
||||
return false;
|
||||
}
|
||||
const auto &buffer = pixmap->buffer();
|
||||
if (buffer.isNull()) {
|
||||
return false;
|
||||
}
|
||||
const QImage &image = buffer->data();
|
||||
if (image.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
xcb_shm_get_image_cookie_t cookie = xcb_shm_get_image_unchecked(connection(), pix, 0, 0, size.width(),
|
||||
size.height(), ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, shm->segment(), 0);
|
||||
|
||||
glGenTextures(1, &m_texture);
|
||||
q->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||
q->setFilter(GL_LINEAR);
|
||||
q->bind();
|
||||
|
||||
ScopedCPointer<xcb_shm_get_image_reply_t> image(xcb_shm_get_image_reply(connection(), cookie, NULL));
|
||||
if (image.isNull()) {
|
||||
const QSize &size = image.size();
|
||||
// TODO: this should be shared with GLTexture(const QImage&, GLenum)
|
||||
GLenum format = 0;
|
||||
switch (image.format()) {
|
||||
case QImage::Format_ARGB32:
|
||||
case QImage::Format_ARGB32_Premultiplied:
|
||||
format = GL_RGBA8;
|
||||
break;
|
||||
case QImage::Format_RGB32:
|
||||
format = GL_RGB8;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: other formats
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
glTexImage2D(m_target, 0, GL_RGBA8, size.width(), size.height(), 0,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, shm->buffer());
|
||||
#endif
|
||||
glTexImage2D(m_target, 0, format, size.width(), size.height(), 0,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
|
||||
|
||||
q->unbind();
|
||||
q->setYInverted(true);
|
||||
|
@ -439,37 +430,32 @@ bool EglWaylandTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_vis
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EglWaylandTexture::update(const QRegion &damage)
|
||||
|
||||
void EglWaylandTexture::updateTexture(WindowPixmap *pixmap)
|
||||
{
|
||||
if (m_referencedPixmap == XCB_PIXMAP_NONE) {
|
||||
return false;
|
||||
if (GLPlatform::instance()->isGLES()) {
|
||||
// FIXME
|
||||
return;
|
||||
}
|
||||
|
||||
Xcb::Shm *shm = m_backend->shm();
|
||||
if (!shm->isValid()) {
|
||||
return false;
|
||||
const auto &buffer = pixmap->buffer();
|
||||
if (buffer.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: optimize by only updating the damaged areas
|
||||
const QRect &damagedRect = damage.boundingRect();
|
||||
xcb_shm_get_image_cookie_t cookie = xcb_shm_get_image_unchecked(connection(), m_referencedPixmap,
|
||||
damagedRect.x(), damagedRect.y(), damagedRect.width(), damagedRect.height(),
|
||||
~0, XCB_IMAGE_FORMAT_Z_PIXMAP, shm->segment(), 0);
|
||||
|
||||
q->bind();
|
||||
|
||||
ScopedCPointer<xcb_shm_get_image_reply_t> image(xcb_shm_get_image_reply(connection(), cookie, NULL));
|
||||
const QImage &image = buffer->data();
|
||||
if (image.isNull()) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
Q_ASSERT(image.size() == m_size);
|
||||
q->bind();
|
||||
const QRegion &damage = pixmap->toplevel()->damage();
|
||||
|
||||
// TODO: other formats
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
glTexSubImage2D(m_target, 0, damagedRect.x(), damagedRect.y(), damagedRect.width(), damagedRect.height(), GL_BGRA, GL_UNSIGNED_BYTE, shm->buffer());
|
||||
#endif
|
||||
|
||||
// TODO: this should be shared with GLTexture::update
|
||||
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
for (const QRect &rect : damage.rects()) {
|
||||
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, im.copy(rect).bits());
|
||||
}
|
||||
q->unbind();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -34,10 +34,6 @@ namespace Wayland {
|
|||
class WaylandBackend;
|
||||
}
|
||||
|
||||
namespace Xcb {
|
||||
class Shm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief OpenGL Backend using Egl on a Wayland surface.
|
||||
*
|
||||
|
@ -46,10 +42,6 @@ namespace Xcb {
|
|||
* system compositor. The OpenGL context is created on the Wayland surface, so for rendering X11 is
|
||||
* not involved.
|
||||
*
|
||||
* At the moment the backend is still rather limited. For getting textures from pixmap it uses the
|
||||
* XShm library. This is currently a hack and only as proof of concept till we support texture from
|
||||
* Wayland buffers. From then on we should use XWayland for texture mapping.
|
||||
*
|
||||
* Also in repainting the backend is currently still rather limited. Only supported mode is fullscreen
|
||||
* repaints, which is obviously not optimal. Best solution is probably to go for buffer_age extension
|
||||
* and make it the only available solution next to fullscreen repaints.
|
||||
|
@ -66,7 +58,6 @@ public:
|
|||
virtual void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
|
||||
virtual bool makeCurrent() override;
|
||||
virtual void doneCurrent() override;
|
||||
Xcb::Shm *shm();
|
||||
virtual bool usesOverlayWindow() const override;
|
||||
|
||||
protected:
|
||||
|
@ -88,7 +79,6 @@ private:
|
|||
int m_bufferAge;
|
||||
Wayland::WaylandBackend *m_wayland;
|
||||
wl_egl_window *m_overlay;
|
||||
QScopedPointer<Xcb::Shm> m_shm;
|
||||
bool m_havePlatformBase;
|
||||
friend class EglWaylandTexture;
|
||||
};
|
||||
|
@ -100,19 +90,15 @@ class EglWaylandTexture : public SceneOpenGL::TexturePrivate
|
|||
{
|
||||
public:
|
||||
virtual ~EglWaylandTexture();
|
||||
virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual) override;
|
||||
virtual bool loadTexture(WindowPixmap *pixmap) override;
|
||||
virtual void updateTexture(WindowPixmap *pixmap) override;
|
||||
virtual OpenGLBackend *backend();
|
||||
virtual bool update(const QRegion &damage);
|
||||
|
||||
private:
|
||||
friend class EglWaylandBackend;
|
||||
EglWaylandTexture(SceneOpenGL::Texture *texture, EglWaylandBackend *backend);
|
||||
SceneOpenGL::Texture *q;
|
||||
EglWaylandBackend *m_backend;
|
||||
/**
|
||||
* The Pixmap of the window content. Get's updated in loadTexture.
|
||||
*/
|
||||
xcb_pixmap_t m_referencedPixmap;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -496,10 +496,8 @@ OpenGLBackend *EglTexture::backend()
|
|||
return m_backend;
|
||||
}
|
||||
|
||||
bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual)
|
||||
bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size)
|
||||
{
|
||||
Q_UNUSED(visual)
|
||||
|
||||
if (pix == XCB_NONE)
|
||||
return false;
|
||||
|
||||
|
@ -528,6 +526,11 @@ bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EglTexture::loadTexture(WindowPixmap *pixmap)
|
||||
{
|
||||
return loadTexture(pixmap->pixmap(), pixmap->toplevel()->size());
|
||||
}
|
||||
|
||||
void KWin::EglTexture::onDamage()
|
||||
{
|
||||
if (options->isGlStrictBinding()) {
|
||||
|
|
|
@ -69,12 +69,13 @@ class EglTexture : public SceneOpenGL::TexturePrivate
|
|||
public:
|
||||
virtual ~EglTexture();
|
||||
virtual void onDamage();
|
||||
virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual) override;
|
||||
virtual bool loadTexture(WindowPixmap *pixmap) override;
|
||||
virtual OpenGLBackend *backend();
|
||||
|
||||
private:
|
||||
friend class EglOnXBackend;
|
||||
EglTexture(SceneOpenGL::Texture *texture, EglOnXBackend *backend);
|
||||
bool loadTexture(xcb_pixmap_t pix, const QSize &size);
|
||||
SceneOpenGL::Texture *q;
|
||||
EglOnXBackend *m_backend;
|
||||
EGLImageKHR m_image;
|
||||
|
|
|
@ -858,6 +858,12 @@ bool GlxTexture::loadTexture(xcb_pixmap_t pixmap, const QSize &size, xcb_visuali
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GlxTexture::loadTexture(WindowPixmap *pixmap)
|
||||
{
|
||||
Toplevel *t = pixmap->toplevel();
|
||||
return loadTexture(pixmap->pixmap(), t->size(), t->visual());
|
||||
}
|
||||
|
||||
OpenGLBackend *GlxTexture::backend()
|
||||
{
|
||||
return m_backend;
|
||||
|
|
|
@ -116,12 +116,13 @@ class GlxTexture : public SceneOpenGL::TexturePrivate
|
|||
public:
|
||||
virtual ~GlxTexture();
|
||||
virtual void onDamage();
|
||||
virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual) override;
|
||||
virtual bool loadTexture(WindowPixmap *pixmap) override;
|
||||
virtual OpenGLBackend *backend();
|
||||
|
||||
private:
|
||||
friend class GlxBackend;
|
||||
GlxTexture(SceneOpenGL::Texture *texture, GlxBackend *backend);
|
||||
bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual);
|
||||
SceneOpenGL::Texture *q;
|
||||
GlxBackend *m_backend;
|
||||
GLXPixmap m_glxpixmap; // the glx pixmap the texture is bound to
|
||||
|
|
6
scene.h
6
scene.h
|
@ -386,14 +386,14 @@ public:
|
|||
* contentsRect tells where inside the complete pixmap the real content is.
|
||||
*/
|
||||
const QRect &contentsRect() const;
|
||||
|
||||
protected:
|
||||
explicit WindowPixmap(Scene::Window *window);
|
||||
/**
|
||||
* @brief Returns the Toplevel this WindowPixmap belongs to.
|
||||
* Note: the Toplevel can change over the lifetime of the WindowPixmap in case the Toplevel is copied to Deleted.
|
||||
*/
|
||||
Toplevel *toplevel();
|
||||
|
||||
protected:
|
||||
explicit WindowPixmap(Scene::Window *window);
|
||||
/**
|
||||
* @return The Window this WindowPixmap belongs to
|
||||
*/
|
||||
|
|
|
@ -1140,17 +1140,23 @@ void SceneOpenGL::Texture::discard()
|
|||
d_ptr = d_func()->backend()->createBackendTexture(this);
|
||||
}
|
||||
|
||||
bool SceneOpenGL::Texture::load(xcb_pixmap_t pix, const QSize &size,
|
||||
xcb_visualid_t visual)
|
||||
bool SceneOpenGL::Texture::load(WindowPixmap *pixmap)
|
||||
{
|
||||
if (pix == XCB_NONE)
|
||||
if (!pixmap->isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// decrease the reference counter for the old texture
|
||||
d_ptr = d_func()->backend()->createBackendTexture(this); //new TexturePrivate();
|
||||
|
||||
Q_D(Texture);
|
||||
return d->loadTexture(pix, size, visual);
|
||||
return d->loadTexture(pixmap);
|
||||
}
|
||||
|
||||
void SceneOpenGL::Texture::updateFromPixmap(WindowPixmap *pixmap)
|
||||
{
|
||||
Q_D(Texture);
|
||||
d->updateTexture(pixmap);
|
||||
}
|
||||
|
||||
//****************************************
|
||||
|
@ -1164,6 +1170,11 @@ SceneOpenGL::TexturePrivate::~TexturePrivate()
|
|||
{
|
||||
}
|
||||
|
||||
void SceneOpenGL::TexturePrivate::updateTexture(WindowPixmap *pixmap)
|
||||
{
|
||||
Q_UNUSED(pixmap)
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// SceneOpenGL::Window
|
||||
//****************************************
|
||||
|
@ -1579,6 +1590,10 @@ bool OpenGLWindowPixmap::bind()
|
|||
{
|
||||
if (!m_texture->isNull()) {
|
||||
if (!toplevel()->damage().isEmpty()) {
|
||||
#if HAVE_WAYLAND
|
||||
updateBuffer();
|
||||
m_texture->updateFromPixmap(this);
|
||||
#endif
|
||||
// mipmaps need to be updated
|
||||
m_texture->setDirty();
|
||||
toplevel()->resetDamage();
|
||||
|
@ -1589,7 +1604,7 @@ bool OpenGLWindowPixmap::bind()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool success = m_texture->load(pixmap(), toplevel()->size(), toplevel()->visual());
|
||||
bool success = m_texture->load(this);
|
||||
|
||||
if (success)
|
||||
toplevel()->resetDamage();
|
||||
|
|
|
@ -157,7 +157,8 @@ class SceneOpenGL::TexturePrivate
|
|||
public:
|
||||
virtual ~TexturePrivate();
|
||||
|
||||
virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual) = 0;
|
||||
virtual bool loadTexture(WindowPixmap *pixmap) = 0;
|
||||
virtual void updateTexture(WindowPixmap *pixmap);
|
||||
virtual OpenGLBackend *backend() = 0;
|
||||
|
||||
protected:
|
||||
|
@ -179,7 +180,8 @@ public:
|
|||
void discard() override final;
|
||||
|
||||
protected:
|
||||
bool load(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t);
|
||||
bool load(WindowPixmap *pixmap);
|
||||
void updateFromPixmap(WindowPixmap *pixmap);
|
||||
|
||||
Texture(TexturePrivate& dd);
|
||||
|
||||
|
|
Loading…
Reference in New Issue