Decouple window pixmaps from scene windows

One of the scene redesign goals is to make wayland surface items
re-usable. So we have the same rendering path for drag-and-drop icons,
software cursors, and window surfaces.

The biggest issue at the moment is that window pixmaps are tightly
coupled with scene windows.

This change de-couples window pixmaps from scene windows. In order to
achieve that, some architecture changes were made.

The WindowPixmap class was replaced with the SurfacePixmap class. A
surface pixmap is created by a surface item.

Under the hood, a SurfacePixmap will create a PlatformSurfaceTexture
object, which contains all the information necessary for the renderer.

The SceneOpenGLTexture class was removed. However, the GLX and the EGL
on X11 backends still mess with GLTexture's internals.
This commit is contained in:
Vlad Zahorodnii 2021-04-09 10:06:04 +03:00
parent 13189463b0
commit 0f2f69ad7c
64 changed files with 1785 additions and 1323 deletions

View file

@ -1,8 +1,13 @@
set(SCENE_OPENGL_BACKEND_SRCS
abstract_egl_backend.cpp
basiceglsurfacetexture_internal.cpp
basiceglsurfacetexture_wayland.cpp
egl_dmabuf.cpp
openglbackend.cpp
texture.cpp
platformopenglsurfacetexture.cpp
platformopenglsurfacetexture_internal.cpp
platformopenglsurfacetexture_wayland.cpp
platformopenglsurfacetexture_x11.cpp
)
include(ECMQtDeclareLoggingCategory)

View file

@ -8,37 +8,25 @@
*/
#include "abstract_egl_backend.h"
#include "egl_dmabuf.h"
#include "kwineglext.h"
#include "composite.h"
#include "egl_context_attribute_builder.h"
#include "options.h"
#include "platform.h"
#include "scene.h"
#include "wayland_server.h"
#include "abstract_wayland_output.h"
#include <KWaylandServer/buffer_interface.h>
#include <KWaylandServer/display.h>
#include <KWaylandServer/surface_interface.h>
// kwin libs
#include <logging.h>
#include <kwinglplatform.h>
#include <kwinglutils.h>
// Qt
#include <QOpenGLContext>
#include <QOpenGLFramebufferObject>
#include <memory>
namespace KWin
{
typedef GLboolean(*eglBindWaylandDisplayWL_func)(EGLDisplay dpy, wl_display *display);
typedef GLboolean(*eglUnbindWaylandDisplayWL_func)(EGLDisplay dpy, wl_display *display);
typedef GLboolean(*eglQueryWaylandBufferWL_func)(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
eglBindWaylandDisplayWL_func eglBindWaylandDisplayWL = nullptr;
eglUnbindWaylandDisplayWL_func eglUnbindWaylandDisplayWL = nullptr;
eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL = nullptr;
static EGLContext s_globalShareContext = EGL_NO_CONTEXT;
static bool isOpenGLES_helper()
@ -108,8 +96,8 @@ AbstractEglBackend::~AbstractEglBackend()
void AbstractEglBackend::teardown()
{
if (eglUnbindWaylandDisplayWL && m_display != EGL_NO_DISPLAY) {
eglUnbindWaylandDisplayWL(m_display, *(WaylandServer::self()->display()));
if (m_functions.eglUnbindWaylandDisplayWL && m_display != EGL_NO_DISPLAY) {
m_functions.eglUnbindWaylandDisplayWL(m_display, *(WaylandServer::self()->display()));
}
destroyGlobalShareContext();
}
@ -206,14 +194,14 @@ void AbstractEglBackend::initWayland()
return;
}
if (hasExtension(QByteArrayLiteral("EGL_WL_bind_wayland_display"))) {
eglBindWaylandDisplayWL = (eglBindWaylandDisplayWL_func)eglGetProcAddress("eglBindWaylandDisplayWL");
eglUnbindWaylandDisplayWL = (eglUnbindWaylandDisplayWL_func)eglGetProcAddress("eglUnbindWaylandDisplayWL");
eglQueryWaylandBufferWL = (eglQueryWaylandBufferWL_func)eglGetProcAddress("eglQueryWaylandBufferWL");
m_functions.eglBindWaylandDisplayWL = (eglBindWaylandDisplayWL_func)eglGetProcAddress("eglBindWaylandDisplayWL");
m_functions.eglUnbindWaylandDisplayWL = (eglUnbindWaylandDisplayWL_func)eglGetProcAddress("eglUnbindWaylandDisplayWL");
m_functions.eglQueryWaylandBufferWL = (eglQueryWaylandBufferWL_func)eglGetProcAddress("eglQueryWaylandBufferWL");
// only bind if not already done
if (waylandServer()->display()->eglDisplay() != eglDisplay()) {
if (!eglBindWaylandDisplayWL(eglDisplay(), *(WaylandServer::self()->display()))) {
eglUnbindWaylandDisplayWL = nullptr;
eglQueryWaylandBufferWL = nullptr;
if (!m_functions.eglBindWaylandDisplayWL(eglDisplay(), *(WaylandServer::self()->display()))) {
m_functions.eglUnbindWaylandDisplayWL = nullptr;
m_functions.eglQueryWaylandBufferWL = nullptr;
} else {
waylandServer()->display()->setEglDisplay(eglDisplay());
}
@ -388,305 +376,4 @@ QSharedPointer<GLTexture> AbstractEglBackend::textureForOutput(AbstractOutput *r
return texture;
}
AbstractEglTexture::AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *backend)
: SceneOpenGLTexturePrivate()
, q(texture)
, m_backend(backend)
, m_image(EGL_NO_IMAGE_KHR)
{
m_target = GL_TEXTURE_2D;
}
AbstractEglTexture::~AbstractEglTexture()
{
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
}
}
OpenGLBackend *AbstractEglTexture::backend()
{
return m_backend;
}
bool AbstractEglTexture::loadTexture(WindowPixmap *pixmap)
{
// FIXME: Refactor this method.
const auto buffer = pixmap->buffer();
if (!buffer) {
if (updateFromFBO(pixmap->fbo())) {
return true;
}
if (loadInternalImageObject(pixmap)) {
return true;
}
return false;
}
// try Wayland loading
if (buffer->linuxDmabufBuffer()) {
return loadDmabufTexture(buffer);
} else if (buffer->shmBuffer()) {
return loadShmTexture(buffer);
}
return loadEglTexture(buffer);
}
void AbstractEglTexture::updateTexture(WindowPixmap *pixmap, const QRegion &region)
{
// FIXME: Refactor this method.
const auto buffer = pixmap->buffer();
if (!buffer) {
if (updateFromFBO(pixmap->fbo())) {
return;
}
if (updateFromInternalImageObject(pixmap, region)) {
return;
}
return;
}
auto s = pixmap->surface();
if (EglDmabufBuffer *dmabuf = static_cast<EglDmabufBuffer *>(buffer->linuxDmabufBuffer())) {
q->bind();
auto images = dmabuf->images();
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) images[0]); //TODO
q->unbind();
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
}
m_image = EGL_NO_IMAGE_KHR; // The wl_buffer has ownership of the image
// The origin in a dmabuf-buffer is at the upper-left corner, so the meaning
// of Y-inverted is the inverse of OpenGL.
q->setYInverted(!(dmabuf->flags() & KWaylandServer::LinuxDmabufUnstableV1Interface::YInverted));
return;
}
if (!buffer->shmBuffer()) {
q->bind();
EGLImageKHR image = attach(buffer);
q->unbind();
if (image != EGL_NO_IMAGE_KHR) {
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
}
m_image = image;
}
return;
}
// shm fallback
const QImage &image = buffer->data();
if (image.isNull() || !s) {
return;
}
Q_ASSERT(image.size() == m_size);
const QRegion damage = s->mapToBuffer(region);
// TODO: this should be shared with GLTexture::update
createTextureSubImage(image, damage);
}
bool AbstractEglTexture::createTextureImage(const QImage &image)
{
if (image.isNull()) {
return false;
}
glGenTextures(1, &m_texture);
q->setFilter(GL_LINEAR);
q->setWrapMode(GL_CLAMP_TO_EDGE);
const QSize &size = image.size();
q->bind();
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;
}
if (GLPlatform::instance()->isGLES()) {
if (s_supportsARGB32 && format == GL_RGBA8) {
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
glTexImage2D(m_target, 0, GL_BGRA_EXT, im.width(), im.height(),
0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.bits());
} else {
const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
glTexImage2D(m_target, 0, GL_RGBA, im.width(), im.height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits());
}
} else {
glTexImage2D(m_target, 0, format, size.width(), size.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
}
q->unbind();
q->setYInverted(true);
m_size = size;
updateMatrix();
return true;
}
void AbstractEglTexture::createTextureSubImage(const QImage &image, const QRegion &damage)
{
q->bind();
if (GLPlatform::instance()->isGLES()) {
if (s_supportsARGB32 && (image.format() == QImage::Format_ARGB32 || image.format() == QImage::Format_ARGB32_Premultiplied)) {
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (const QRect &rect : damage) {
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.copy(rect).constBits());
}
} else {
const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
for (const QRect &rect : damage) {
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
GL_RGBA, GL_UNSIGNED_BYTE, im.copy(rect).constBits());
}
}
} else {
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (const QRect &rect : damage) {
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
GL_BGRA, GL_UNSIGNED_BYTE, im.copy(rect).constBits());
}
}
q->unbind();
}
bool AbstractEglTexture::loadShmTexture(const QPointer< KWaylandServer::BufferInterface > &buffer)
{
return createTextureImage(buffer->data());
}
bool AbstractEglTexture::loadEglTexture(const QPointer< KWaylandServer::BufferInterface > &buffer)
{
if (!eglQueryWaylandBufferWL) {
return false;
}
if (!buffer->resource()) {
return false;
}
glGenTextures(1, &m_texture);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_LINEAR);
q->bind();
m_image = attach(buffer);
q->unbind();
if (EGL_NO_IMAGE_KHR == m_image) {
qCDebug(KWIN_OPENGL) << "failed to create egl image";
q->discard();
return false;
}
return true;
}
bool AbstractEglTexture::loadDmabufTexture(const QPointer< KWaylandServer::BufferInterface > &buffer)
{
auto *dmabuf = static_cast<EglDmabufBuffer *>(buffer->linuxDmabufBuffer());
if (!dmabuf || dmabuf->images().isEmpty() || dmabuf->images().constFirst() == EGL_NO_IMAGE_KHR) {
qCritical(KWIN_OPENGL) << "Invalid dmabuf-based wl_buffer";
q->discard();
return false;
}
Q_ASSERT(m_image == EGL_NO_IMAGE_KHR);
glGenTextures(1, &m_texture);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_NEAREST);
q->bind();
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) dmabuf->images().constFirst());
q->unbind();
m_size = dmabuf->size();
q->setYInverted(!(dmabuf->flags() & KWaylandServer::LinuxDmabufUnstableV1Interface::YInverted));
updateMatrix();
return true;
}
bool AbstractEglTexture::loadInternalImageObject(WindowPixmap *pixmap)
{
return createTextureImage(pixmap->internalImage());
}
EGLImageKHR AbstractEglTexture::attach(const QPointer< KWaylandServer::BufferInterface > &buffer)
{
EGLint format, yInverted;
eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_TEXTURE_FORMAT, &format);
if (format != EGL_TEXTURE_RGB && format != EGL_TEXTURE_RGBA) {
qCDebug(KWIN_OPENGL) << "Unsupported texture format: " << format;
return EGL_NO_IMAGE_KHR;
}
if (!eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_WAYLAND_Y_INVERTED_WL, &yInverted)) {
// if EGL_WAYLAND_Y_INVERTED_WL is not supported wl_buffer should be treated as if value were EGL_TRUE
yInverted = EGL_TRUE;
}
const EGLint attribs[] = {
EGL_WAYLAND_PLANE_WL, 0,
EGL_NONE
};
EGLImageKHR image = eglCreateImageKHR(m_backend->eglDisplay(), EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL,
(EGLClientBuffer)buffer->resource(), attribs);
if (image != EGL_NO_IMAGE_KHR) {
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
m_size = buffer->size();
updateMatrix();
q->setYInverted(yInverted);
}
return image;
}
bool AbstractEglTexture::updateFromFBO(const QSharedPointer<QOpenGLFramebufferObject> &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;
}
static QRegion scale(const QRegion &region, qreal scaleFactor)
{
if (scaleFactor == 1) {
return region;
}
QRegion scaled;
for (const QRect &rect : region) {
scaled += QRect(rect.topLeft() * scaleFactor, rect.size() * scaleFactor);
}
return scaled;
}
bool AbstractEglTexture::updateFromInternalImageObject(WindowPixmap *pixmap, const QRegion &region)
{
const QImage image = pixmap->internalImage();
if (image.isNull()) {
return false;
}
if (m_size != image.size()) {
glDeleteTextures(1, &m_texture);
return loadInternalImageObject(pixmap);
}
createTextureSubImage(image, scale(region, image.devicePixelRatio()));
return true;
}
}

View file

@ -9,21 +9,27 @@
#ifndef KWIN_ABSTRACT_EGL_BACKEND_H
#define KWIN_ABSTRACT_EGL_BACKEND_H
#include "openglbackend.h"
#include "texture.h"
#include <QObject>
#include <epoxy/egl.h>
class QOpenGLFramebufferObject;
namespace KWaylandServer
{
class BufferInterface;
}
struct wl_display;
struct wl_resource;
namespace KWin
{
typedef GLboolean(*eglBindWaylandDisplayWL_func)(EGLDisplay dpy, wl_display *display);
typedef GLboolean(*eglUnbindWaylandDisplayWL_func)(EGLDisplay dpy, wl_display *display);
typedef GLboolean(*eglQueryWaylandBufferWL_func)(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
struct AbstractEglBackendFunctions
{
eglBindWaylandDisplayWL_func eglBindWaylandDisplayWL = nullptr;
eglUnbindWaylandDisplayWL_func eglUnbindWaylandDisplayWL = nullptr;
eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL = nullptr;
};
class EglDmabuf;
class AbstractOutput;
@ -35,6 +41,9 @@ public:
bool makeCurrent() override;
void doneCurrent() override;
const AbstractEglBackendFunctions *functions() const {
return &m_functions;
}
EGLDisplay eglDisplay() const {
return m_display;
}
@ -80,6 +89,7 @@ protected:
private:
void teardown();
AbstractEglBackendFunctions m_functions;
EGLDisplay m_display = EGL_NO_DISPLAY;
EGLSurface m_surface = EGL_NO_SURFACE;
EGLContext m_context = EGL_NO_CONTEXT;
@ -91,41 +101,6 @@ private:
static AbstractEglBackend * s_primaryBackend;
};
class KWIN_EXPORT AbstractEglTexture : public SceneOpenGLTexturePrivate
{
public:
~AbstractEglTexture() override;
bool loadTexture(WindowPixmap *pixmap) override;
void updateTexture(WindowPixmap *pixmap, const QRegion &region) override;
OpenGLBackend *backend() override;
protected:
AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *backend);
EGLImageKHR image() const {
return m_image;
}
void setImage(const EGLImageKHR &img) {
m_image = img;
}
SceneOpenGLTexture *texture() const {
return q;
}
private:
void createTextureSubImage(const QImage &image, const QRegion &damage);
bool createTextureImage(const QImage &image);
bool loadShmTexture(const QPointer<KWaylandServer::BufferInterface> &buffer);
bool loadEglTexture(const QPointer<KWaylandServer::BufferInterface> &buffer);
bool loadDmabufTexture(const QPointer< KWaylandServer::BufferInterface > &buffer);
bool loadInternalImageObject(WindowPixmap *pixmap);
EGLImageKHR attach(const QPointer<KWaylandServer::BufferInterface> &buffer);
bool updateFromFBO(const QSharedPointer<QOpenGLFramebufferObject> &fbo);
bool updateFromInternalImageObject(WindowPixmap *pixmap, const QRegion &region);
SceneOpenGLTexture *q;
AbstractEglBackend *m_backend;
EGLImageKHR m_image;
};
}
#endif

View file

@ -0,0 +1,91 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "basiceglsurfacetexture_internal.h"
#include "kwingltexture.h"
#include "logging.h"
#include "surfaceitem_internal.h"
#include <QOpenGLFramebufferObject>
namespace KWin
{
BasicEGLSurfaceTextureInternal::BasicEGLSurfaceTextureInternal(OpenGLBackend *backend,
SurfacePixmapInternal *pixmap)
: PlatformOpenGLSurfaceTextureInternal(backend, pixmap)
{
}
bool BasicEGLSurfaceTextureInternal::create()
{
if (updateFromFramebuffer()) {
return true;
} else if (updateFromImage(m_pixmap->image().rect())) {
return true;
} else {
qCDebug(KWIN_OPENGL) << "Failed to create surface texture for internal window";
return false;
}
}
void BasicEGLSurfaceTextureInternal::update(const QRegion &region)
{
if (updateFromFramebuffer()) {
return;
} else if (updateFromImage(region)) {
return;
} else {
qCDebug(KWIN_OPENGL) << "Failed to update surface texture for internal window";
}
}
bool BasicEGLSurfaceTextureInternal::updateFromFramebuffer()
{
const QOpenGLFramebufferObject *fbo = m_pixmap->fbo();
if (!fbo) {
return false;
}
m_texture.reset(new GLTexture(fbo->texture(), 0, fbo->size()));
m_texture->setWrapMode(GL_CLAMP_TO_EDGE);
m_texture->setFilter(GL_LINEAR);
m_texture->setYInverted(false);
return true;
}
static QRegion scale(const QRegion &region, qreal scaleFactor)
{
if (scaleFactor == 1) {
return region;
}
QRegion scaled;
for (const QRect &rect : region) {
scaled += QRect(rect.topLeft() * scaleFactor, rect.size() * scaleFactor);
}
return scaled;
}
bool BasicEGLSurfaceTextureInternal::updateFromImage(const QRegion &region)
{
const QImage image = m_pixmap->image();
if (image.isNull()) {
return false;
}
if (!m_texture) {
m_texture.reset(new GLTexture(image));
} else {
const QRegion nativeRegion = scale(region, image.devicePixelRatio());
for (const QRect &rect : nativeRegion) {
m_texture->update(image, rect.topLeft(), rect);
}
}
return true;
}
} // namespace KWin

View file

@ -0,0 +1,27 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "platformopenglsurfacetexture_internal.h"
namespace KWin
{
class KWIN_EXPORT BasicEGLSurfaceTextureInternal : public PlatformOpenGLSurfaceTextureInternal
{
public:
BasicEGLSurfaceTextureInternal(OpenGLBackend *backend, SurfacePixmapInternal *pixmap);
bool create() override;
void update(const QRegion &region) override;
private:
bool updateFromFramebuffer();
bool updateFromImage(const QRegion &region);
};
} // namespace KWin

View file

@ -0,0 +1,244 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "basiceglsurfacetexture_wayland.h"
#include "egl_dmabuf.h"
#include "kwineglext.h"
#include "kwingltexture.h"
#include "logging.h"
#include "surfaceitem_wayland.h"
#include <epoxy/gl.h>
#include <KWaylandServer/buffer_interface.h>
#include <KWaylandServer/linuxdmabuf_v1_interface.h>
#include <KWaylandServer/surface_interface.h>
namespace KWin
{
BasicEGLSurfaceTextureWayland::BasicEGLSurfaceTextureWayland(OpenGLBackend *backend,
SurfacePixmapWayland *pixmap)
: PlatformOpenGLSurfaceTextureWayland(backend, pixmap)
{
}
BasicEGLSurfaceTextureWayland::~BasicEGLSurfaceTextureWayland()
{
destroy();
}
AbstractEglBackend *BasicEGLSurfaceTextureWayland::backend() const
{
return static_cast<AbstractEglBackend *>(m_backend);
}
bool BasicEGLSurfaceTextureWayland::create()
{
KWaylandServer::BufferInterface *buffer = m_pixmap->buffer();
if (Q_UNLIKELY(!buffer)) {
return false;
}
if (buffer->linuxDmabufBuffer()) {
return loadDmabufTexture(buffer);
} else if (buffer->shmBuffer()) {
return loadShmTexture(buffer);
} else {
return loadEglTexture(buffer);
}
}
void BasicEGLSurfaceTextureWayland::destroy()
{
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(backend()->eglDisplay(), m_image);
m_image = EGL_NO_IMAGE_KHR;
}
if (m_textureId) {
glDeleteTextures(1, &m_textureId);
m_textureId = 0;
}
m_texture.reset();
m_bufferType = BufferType::None;
}
void BasicEGLSurfaceTextureWayland::update(const QRegion &region)
{
KWaylandServer::BufferInterface *buffer = m_pixmap->buffer();
if (Q_UNLIKELY(!buffer)) {
return;
}
if (buffer->linuxDmabufBuffer()) {
updateDmabufTexture(buffer);
} else if (buffer->shmBuffer()) {
updateShmTexture(buffer, region);
} else {
updateEglTexture(buffer);
}
}
bool BasicEGLSurfaceTextureWayland::loadShmTexture(KWaylandServer::BufferInterface *buffer)
{
const QImage &image = buffer->data();
if (Q_UNLIKELY(image.isNull())) {
return false;
}
m_texture.reset(new GLTexture(image));
m_texture->setFilter(GL_LINEAR);
m_texture->setWrapMode(GL_CLAMP_TO_EDGE);
m_texture->setYInverted(true);
m_bufferType = BufferType::Shm;
return true;
}
void BasicEGLSurfaceTextureWayland::updateShmTexture(KWaylandServer::BufferInterface *buffer, const QRegion &region)
{
if (Q_UNLIKELY(m_bufferType != BufferType::Shm)) {
destroy();
create();
return;
}
KWaylandServer::SurfaceInterface *surface = m_pixmap->surface();
if (Q_UNLIKELY(!surface)) {
return;
}
const QImage &image = buffer->data();
if (Q_UNLIKELY(image.isNull())) {
return;
}
const QRegion damage = surface->mapToBuffer(region);
for (const QRect &rect : damage) {
m_texture->update(image, rect.topLeft(), rect);
}
}
bool BasicEGLSurfaceTextureWayland::loadEglTexture(KWaylandServer::BufferInterface *buffer)
{
const AbstractEglBackendFunctions *funcs = backend()->functions();
if (Q_UNLIKELY(!funcs->eglQueryWaylandBufferWL)) {
return false;
}
if (Q_UNLIKELY(!buffer->resource())) {
return false;
}
glGenTextures(1, &m_textureId);
m_texture.reset(new GLTexture(m_textureId, 0, buffer->size()));
m_texture->setWrapMode(GL_CLAMP_TO_EDGE);
m_texture->setFilter(GL_LINEAR);
m_texture->bind();
m_image = attach(buffer);
m_texture->unbind();
m_bufferType = BufferType::Egl;
if (EGL_NO_IMAGE_KHR == m_image) {
qCDebug(KWIN_OPENGL) << "failed to create egl image";
m_texture.reset();
return false;
}
return true;
}
void BasicEGLSurfaceTextureWayland::updateEglTexture(KWaylandServer::BufferInterface *buffer)
{
if (Q_UNLIKELY(m_bufferType != BufferType::Egl)) {
destroy();
create();
return;
}
m_texture->bind();
EGLImageKHR image = attach(buffer);
m_texture->unbind();
if (image != EGL_NO_IMAGE_KHR) {
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(backend()->eglDisplay(), m_image);
}
m_image = image;
}
}
bool BasicEGLSurfaceTextureWayland::loadDmabufTexture(KWaylandServer::BufferInterface *buffer)
{
auto dmabuf = static_cast<EglDmabufBuffer *>(buffer->linuxDmabufBuffer());
if (Q_UNLIKELY(dmabuf->images().constFirst() == EGL_NO_IMAGE_KHR)) {
qCritical(KWIN_OPENGL) << "Invalid dmabuf-based wl_buffer";
return false;
}
glGenTextures(1, &m_textureId);
m_texture.reset(new GLTexture(m_textureId, 0, dmabuf->size()));
m_texture->setWrapMode(GL_CLAMP_TO_EDGE);
m_texture->setFilter(GL_NEAREST);
m_texture->bind();
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(dmabuf->images().constFirst()));
m_texture->unbind();
m_texture->setYInverted(!(dmabuf->flags() & KWaylandServer::LinuxDmabufUnstableV1Interface::YInverted));
m_bufferType = BufferType::DmaBuf;
return true;
}
void BasicEGLSurfaceTextureWayland::updateDmabufTexture(KWaylandServer::BufferInterface *buffer)
{
if (Q_UNLIKELY(m_bufferType != BufferType::DmaBuf)) {
destroy();
create();
return;
}
auto dmabuf = static_cast<EglDmabufBuffer *>(buffer->linuxDmabufBuffer());
m_texture->bind();
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(dmabuf->images().constFirst()));
m_texture->unbind();
// The origin in a dmabuf-buffer is at the upper-left corner, so the meaning
// of Y-inverted is the inverse of OpenGL.
m_texture->setYInverted(!(dmabuf->flags() & KWaylandServer::LinuxDmabufUnstableV1Interface::YInverted));
}
EGLImageKHR BasicEGLSurfaceTextureWayland::attach(KWaylandServer::BufferInterface *buffer)
{
const AbstractEglBackendFunctions *funcs = backend()->functions();
EGLint format;
funcs->eglQueryWaylandBufferWL(backend()->eglDisplay(), buffer->resource(),
EGL_TEXTURE_FORMAT, &format);
if (format != EGL_TEXTURE_RGB && format != EGL_TEXTURE_RGBA) {
qCDebug(KWIN_OPENGL) << "Unsupported texture format: " << format;
return EGL_NO_IMAGE_KHR;
}
EGLint yInverted;
if (!funcs->eglQueryWaylandBufferWL(backend()->eglDisplay(), buffer->resource(),
EGL_WAYLAND_Y_INVERTED_WL, &yInverted)) {
// If EGL_WAYLAND_Y_INVERTED_WL is not supported wl_buffer should be treated as
// if value were EGL_TRUE.
yInverted = EGL_TRUE;
}
const EGLint attribs[] = {
EGL_WAYLAND_PLANE_WL, 0,
EGL_NONE
};
EGLImageKHR image = eglCreateImageKHR(backend()->eglDisplay(), EGL_NO_CONTEXT,
EGL_WAYLAND_BUFFER_WL,
static_cast<EGLClientBuffer>(buffer->resource()), attribs);
if (image != EGL_NO_IMAGE_KHR) {
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(image));
m_texture->setYInverted(yInverted);
}
return image;
}
} // namespace KWin

View file

@ -0,0 +1,51 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "platformopenglsurfacetexture_wayland.h"
#include <epoxy/egl.h>
namespace KWin
{
class AbstractEglBackend;
class KWIN_EXPORT BasicEGLSurfaceTextureWayland : public PlatformOpenGLSurfaceTextureWayland
{
public:
BasicEGLSurfaceTextureWayland(OpenGLBackend *backend, SurfacePixmapWayland *pixmap);
~BasicEGLSurfaceTextureWayland() override;
AbstractEglBackend *backend() const;
bool create() override;
void update(const QRegion &region) override;
private:
bool loadShmTexture(KWaylandServer::BufferInterface *buffer);
void updateShmTexture(KWaylandServer::BufferInterface *buffer, const QRegion &region);
bool loadEglTexture(KWaylandServer::BufferInterface *buffer);
void updateEglTexture(KWaylandServer::BufferInterface *buffer);
bool loadDmabufTexture(KWaylandServer::BufferInterface *buffer);
void updateDmabufTexture(KWaylandServer::BufferInterface *buffer);
EGLImageKHR attach(KWaylandServer::BufferInterface *buffer);
void destroy();
enum class BufferType {
None,
Shm,
DmaBuf,
Egl,
};
EGLImageKHR m_image = EGL_NO_IMAGE_KHR;
BufferType m_bufferType = BufferType::None;
GLuint m_textureId = 0;
};
} // namespace KWin

View file

@ -103,4 +103,22 @@ bool OpenGLBackend::directScanoutAllowed(int screen) const
return false;
}
PlatformSurfaceTexture *OpenGLBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
Q_UNUSED(pixmap)
return nullptr;
}
PlatformSurfaceTexture *OpenGLBackend::createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap)
{
Q_UNUSED(pixmap)
return nullptr;
}
PlatformSurfaceTexture *OpenGLBackend::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
Q_UNUSED(pixmap)
return nullptr;
}
}

View file

@ -19,11 +19,11 @@ namespace KWin
class AbstractOutput;
class OpenGLBackend;
class OverlayWindow;
class SceneOpenGL;
class SceneOpenGLTexture;
class SceneOpenGLTexturePrivate;
class PlatformSurfaceTexture;
class SurfaceItem;
class WindowPixmap;
class SurfacePixmapInternal;
class SurfacePixmapX11;
class SurfacePixmapWayland;
class GLTexture;
/**
@ -49,7 +49,10 @@ public:
virtual void init() = 0;
virtual void screenGeometryChanged(const QSize &size) = 0;
virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) = 0;
virtual PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap);
virtual PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap);
virtual PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap);
/**
* Notifies about starting to paint.

View file

@ -0,0 +1,37 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "platformopenglsurfacetexture.h"
#include "kwingltexture.h"
namespace KWin
{
PlatformOpenGLSurfaceTexture::PlatformOpenGLSurfaceTexture(OpenGLBackend *backend)
: m_backend(backend)
{
}
PlatformOpenGLSurfaceTexture::~PlatformOpenGLSurfaceTexture()
{
}
bool PlatformOpenGLSurfaceTexture::isValid() const
{
return m_texture;
}
OpenGLBackend *PlatformOpenGLSurfaceTexture::backend() const
{
return m_backend;
}
GLTexture *PlatformOpenGLSurfaceTexture::texture() const
{
return m_texture.data();
}
} // namespace KWin

View file

@ -0,0 +1,36 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "surfaceitem.h"
namespace KWin
{
class GLTexture;
class OpenGLBackend;
class KWIN_EXPORT PlatformOpenGLSurfaceTexture : public PlatformSurfaceTexture
{
public:
explicit PlatformOpenGLSurfaceTexture(OpenGLBackend *backend);
~PlatformOpenGLSurfaceTexture() override;
bool isValid() const override;
OpenGLBackend *backend() const;
GLTexture *texture() const;
virtual bool create() = 0;
virtual void update(const QRegion &region) = 0;
protected:
OpenGLBackend *m_backend;
QScopedPointer<GLTexture> m_texture;
};
} // namespace KWin

View file

@ -0,0 +1,19 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "platformopenglsurfacetexture_internal.h"
namespace KWin
{
PlatformOpenGLSurfaceTextureInternal::PlatformOpenGLSurfaceTextureInternal(OpenGLBackend *backend,
SurfacePixmapInternal *pixmap)
: PlatformOpenGLSurfaceTexture(backend)
, m_pixmap(pixmap)
{
}
} // namespace KWin

View file

@ -0,0 +1,23 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "platformopenglsurfacetexture.h"
namespace KWin
{
class KWIN_EXPORT PlatformOpenGLSurfaceTextureInternal : public PlatformOpenGLSurfaceTexture
{
public:
PlatformOpenGLSurfaceTextureInternal(OpenGLBackend *backend, SurfacePixmapInternal *pixmap);
protected:
SurfacePixmapInternal *m_pixmap;
};
} // namespace KWin

View file

@ -0,0 +1,19 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "platformopenglsurfacetexture_wayland.h"
namespace KWin
{
PlatformOpenGLSurfaceTextureWayland::PlatformOpenGLSurfaceTextureWayland(OpenGLBackend *backend,
SurfacePixmapWayland *pixmap)
: PlatformOpenGLSurfaceTexture(backend)
, m_pixmap(pixmap)
{
}
} // namespace KWin

View file

@ -0,0 +1,23 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "platformopenglsurfacetexture.h"
namespace KWin
{
class KWIN_EXPORT PlatformOpenGLSurfaceTextureWayland : public PlatformOpenGLSurfaceTexture
{
public:
PlatformOpenGLSurfaceTextureWayland(OpenGLBackend *backend, SurfacePixmapWayland *pixmap);
protected:
SurfacePixmapWayland *m_pixmap;
};
} // namespace KWin

View file

@ -0,0 +1,19 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "platformopenglsurfacetexture_x11.h"
namespace KWin
{
PlatformOpenGLSurfaceTextureX11::PlatformOpenGLSurfaceTextureX11(OpenGLBackend *backend,
SurfacePixmapX11 *pixmap)
: PlatformOpenGLSurfaceTexture(backend)
, m_pixmap(pixmap)
{
}
} // namespace KWin

View file

@ -0,0 +1,23 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "platformopenglsurfacetexture.h"
namespace KWin
{
class KWIN_EXPORT PlatformOpenGLSurfaceTextureX11 : public PlatformOpenGLSurfaceTexture
{
public:
PlatformOpenGLSurfaceTextureX11(OpenGLBackend *backend, SurfacePixmapX11 *pixmap);
protected:
SurfacePixmapX11 *m_pixmap;
};
} // namespace KWin

View file

@ -1,70 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
SPDX-FileCopyrightText: 2009, 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "texture.h"
#include "openglbackend.h"
#include "scene.h"
namespace KWin
{
SceneOpenGLTexture::SceneOpenGLTexture(OpenGLBackend *backend)
: GLTexture(*backend->createBackendTexture(this))
{
}
SceneOpenGLTexture::~SceneOpenGLTexture()
{
}
SceneOpenGLTexture& SceneOpenGLTexture::operator = (const SceneOpenGLTexture& tex)
{
d_ptr = tex.d_ptr;
return *this;
}
void SceneOpenGLTexture::discard()
{
d_ptr = d_func()->backend()->createBackendTexture(this);
}
bool SceneOpenGLTexture::load(WindowPixmap *pixmap)
{
if (!pixmap->isValid()) {
return false;
}
// decrease the reference counter for the old texture
d_ptr = d_func()->backend()->createBackendTexture(this); //new TexturePrivate();
Q_D(SceneOpenGLTexture);
return d->loadTexture(pixmap);
}
void SceneOpenGLTexture::updateFromPixmap(WindowPixmap *pixmap, const QRegion &region)
{
Q_D(SceneOpenGLTexture);
d->updateTexture(pixmap, region);
}
SceneOpenGLTexturePrivate::SceneOpenGLTexturePrivate()
{
}
SceneOpenGLTexturePrivate::~SceneOpenGLTexturePrivate()
{
}
void SceneOpenGLTexturePrivate::updateTexture(WindowPixmap *pixmap, const QRegion &region)
{
Q_UNUSED(pixmap)
Q_UNUSED(region)
}
}

View file

@ -1,59 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
SPDX-FileCopyrightText: 2009, 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <kwingltexture.h>
#include <kwingltexture_p.h>
namespace KWin
{
class OpenGLBackend;
class SceneOpenGLTexturePrivate;
class WindowPixmap;
class SceneOpenGLTexture : public GLTexture
{
public:
explicit SceneOpenGLTexture(OpenGLBackend *backend);
~SceneOpenGLTexture() override;
SceneOpenGLTexture & operator = (const SceneOpenGLTexture& tex);
void discard() override final;
private:
SceneOpenGLTexture(SceneOpenGLTexturePrivate& dd);
bool load(WindowPixmap *pixmap);
void updateFromPixmap(WindowPixmap *pixmap, const QRegion &region);
Q_DECLARE_PRIVATE(SceneOpenGLTexture)
friend class OpenGLWindowPixmap;
};
class SceneOpenGLTexturePrivate : public GLTexturePrivate
{
public:
~SceneOpenGLTexturePrivate() override;
virtual bool loadTexture(WindowPixmap *pixmap) = 0;
virtual void updateTexture(WindowPixmap *pixmap, const QRegion &region);
virtual OpenGLBackend *backend() = 0;
protected:
SceneOpenGLTexturePrivate();
private:
Q_DISABLE_COPY(SceneOpenGLTexturePrivate)
};
}

View file

@ -1,4 +1,9 @@
set(SCENE_QPAINTER_BACKEND_SRCS qpainterbackend.cpp)
set(SCENE_QPAINTER_BACKEND_SRCS
platformqpaintersurfacetexture.cpp
platformqpaintersurfacetexture_internal.cpp
platformqpaintersurfacetexture_wayland.cpp
qpainterbackend.cpp
)
include(ECMQtDeclareLoggingCategory)
ecm_qt_declare_logging_category(SCENE_QPAINTER_BACKEND_SRCS
@ -13,5 +18,5 @@ ecm_qt_declare_logging_category(SCENE_QPAINTER_BACKEND_SRCS
)
add_library(SceneQPainterBackend STATIC ${SCENE_QPAINTER_BACKEND_SRCS})
target_link_libraries(SceneQPainterBackend Qt::Core)
target_include_directories(SceneQPainterBackend PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(SceneQPainterBackend Qt::Core Qt::Widgets KF5::CoreAddons KF5::ConfigCore KF5::WindowSystem Plasma::KWaylandServer)
target_include_directories(SceneQPainterBackend PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src)

View file

@ -0,0 +1,32 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "platformqpaintersurfacetexture.h"
namespace KWin
{
PlatformQPainterSurfaceTexture::PlatformQPainterSurfaceTexture(QPainterBackend *backend)
: m_backend(backend)
{
}
bool PlatformQPainterSurfaceTexture::isValid() const
{
return !m_image.isNull();
}
QPainterBackend *PlatformQPainterSurfaceTexture::backend() const
{
return m_backend;
}
QImage PlatformQPainterSurfaceTexture::image() const
{
return m_image;
}
} // namespace KWin

View file

@ -0,0 +1,36 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "surfaceitem.h"
#include <QImage>
namespace KWin
{
class QPainterBackend;
class KWIN_EXPORT PlatformQPainterSurfaceTexture : public PlatformSurfaceTexture
{
public:
explicit PlatformQPainterSurfaceTexture(QPainterBackend *backend);
bool isValid() const override;
QPainterBackend *backend() const;
QImage image() const;
virtual bool create() = 0;
virtual void update(const QRegion &region) = 0;
protected:
QPainterBackend *m_backend;
QImage m_image;
};
} // namespace KWin

View file

@ -0,0 +1,32 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "platformqpaintersurfacetexture_internal.h"
#include "surfaceitem_internal.h"
namespace KWin
{
PlatformQPainterSurfaceTextureInternal::PlatformQPainterSurfaceTextureInternal(QPainterBackend *backend,
SurfacePixmapInternal *pixmap)
: PlatformQPainterSurfaceTexture(backend)
, m_pixmap(pixmap)
{
}
bool PlatformQPainterSurfaceTextureInternal::create()
{
update(QRegion());
return !m_image.isNull();
}
void PlatformQPainterSurfaceTextureInternal::update(const QRegion &region)
{
Q_UNUSED(region)
m_image = m_pixmap->image();
}
} // namespace KWin

View file

@ -0,0 +1,26 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "platformqpaintersurfacetexture.h"
namespace KWin
{
class KWIN_EXPORT PlatformQPainterSurfaceTextureInternal : public PlatformQPainterSurfaceTexture
{
public:
PlatformQPainterSurfaceTextureInternal(QPainterBackend *backend, SurfacePixmapInternal *pixmap);
bool create() override;
void update(const QRegion &region) override;
private:
SurfacePixmapInternal *m_pixmap;
};
} // namespace KWin

View file

@ -0,0 +1,55 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "platformqpaintersurfacetexture_wayland.h"
#include "surfaceitem_wayland.h"
#include <KWaylandServer/buffer_interface.h>
#include <KWaylandServer/surface_interface.h>
#include <QPainter>
namespace KWin
{
PlatformQPainterSurfaceTextureWayland::PlatformQPainterSurfaceTextureWayland(QPainterBackend *backend,
SurfacePixmapWayland *pixmap)
: PlatformQPainterSurfaceTexture(backend)
, m_pixmap(pixmap)
{
}
bool PlatformQPainterSurfaceTextureWayland::create()
{
KWaylandServer::BufferInterface *buffer = m_pixmap->buffer();
if (Q_LIKELY(buffer)) {
// The buffer data is copied as the buffer interface returns a QImage
// which doesn't own the data of the underlying wl_shm_buffer object.
m_image = buffer->data().copy();
}
return !m_image.isNull();
}
void PlatformQPainterSurfaceTextureWayland::update(const QRegion &region)
{
KWaylandServer::BufferInterface *buffer = m_pixmap->buffer();
KWaylandServer::SurfaceInterface *surface = m_pixmap->surface();
if (Q_UNLIKELY(!buffer || !surface)) {
return;
}
const QImage image = buffer->data();
const QRegion dirtyRegion = surface->mapToBuffer(region);
QPainter painter(&m_image);
// The buffer data is copied as the buffer interface returns a QImage
// which doesn't own the data of the underlying wl_shm_buffer object.
for (const QRect &rect : dirtyRegion) {
painter.drawImage(rect, image, rect);
}
}
} // namespace KWin

View file

@ -0,0 +1,26 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "platformqpaintersurfacetexture.h"
namespace KWin
{
class KWIN_EXPORT PlatformQPainterSurfaceTextureWayland : public PlatformQPainterSurfaceTexture
{
public:
PlatformQPainterSurfaceTextureWayland(QPainterBackend *backend, SurfacePixmapWayland *pixmap);
bool create() override;
void update(const QRegion &region) override;
private:
SurfacePixmapWayland *m_pixmap;
};
} // namespace KWin

View file

@ -7,6 +7,8 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qpainterbackend.h"
#include "platformqpaintersurfacetexture_internal.h"
#include "platformqpaintersurfacetexture_wayland.h"
#include <logging.h>
#include <QtGlobal>
@ -23,6 +25,16 @@ QPainterBackend::~QPainterBackend()
{
}
PlatformSurfaceTexture *QPainterBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return new PlatformQPainterSurfaceTextureInternal(this, pixmap);
}
PlatformSurfaceTexture *QPainterBackend::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return new PlatformQPainterSurfaceTextureWayland(this, pixmap);
}
void QPainterBackend::screenGeometryChanged(const QSize &size)
{
Q_UNUSED(size)

View file

@ -17,10 +17,18 @@ class QString;
namespace KWin
{
class PlatformSurfaceTexture;
class SurfacePixmapInternal;
class SurfacePixmapWayland;
class QPainterBackend
{
public:
virtual ~QPainterBackend();
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap);
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap);
virtual void endFrame(int screenId, int mask, const QRegion &damage) = 0;
virtual void beginFrame(int screenId) = 0;
/**

View file

@ -1,4 +1,7 @@
set(xrenderbackend_SOURCES xrenderbackend.cpp)
set(xrenderbackend_SOURCES
platformxrendersurfacetexture_x11.cpp
xrenderbackend.cpp
)
ecm_qt_declare_logging_category(xrenderbackend_SOURCES
HEADER logging.h

View file

@ -0,0 +1,59 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "platformxrendersurfacetexture_x11.h"
#include "main.h"
#include "surfaceitem_x11.h"
#include <kwinxrenderutils.h>
namespace KWin
{
PlatformXrenderSurfaceTextureX11::PlatformXrenderSurfaceTextureX11(SurfacePixmapX11 *pixmap)
: m_pixmap(pixmap)
{
}
PlatformXrenderSurfaceTextureX11::~PlatformXrenderSurfaceTextureX11()
{
if (m_picture != XCB_RENDER_PICTURE_NONE) {
xcb_render_free_picture(kwinApp()->x11Connection(), m_picture);
}
}
bool PlatformXrenderSurfaceTextureX11::isValid() const
{
return m_picture != XCB_RENDER_PICTURE_NONE;
}
xcb_render_picture_t PlatformXrenderSurfaceTextureX11::picture() const
{
return m_picture;
}
bool PlatformXrenderSurfaceTextureX11::create()
{
if (m_picture != XCB_RENDER_PICTURE_NONE) {
return true;
}
const xcb_pixmap_t pixmap = m_pixmap->pixmap();
if (pixmap == XCB_PIXMAP_NONE) {
return false;
}
xcb_render_pictformat_t format = XRenderUtils::findPictFormat(m_pixmap->visual());
if (format == XCB_NONE) {
return false;
}
m_picture = xcb_generate_id(kwinApp()->x11Connection());
xcb_render_create_picture(kwinApp()->x11Connection(), m_picture, pixmap, format, 0, nullptr);
return true;
}
} // namespace KWin

View file

@ -0,0 +1,32 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "surfaceitem_x11.h"
#include <xcb/render.h>
namespace KWin
{
class KWIN_EXPORT PlatformXrenderSurfaceTextureX11 : public PlatformSurfaceTexture
{
public:
explicit PlatformXrenderSurfaceTextureX11(SurfacePixmapX11 *pixmap);
~PlatformXrenderSurfaceTextureX11() override;
bool isValid() const override;
bool create();
xcb_render_picture_t picture() const;
private:
SurfacePixmapX11 *m_pixmap;
xcb_render_picture_t m_picture = XCB_RENDER_PICTURE_NONE;
};
} // namespace KWin

View file

@ -7,6 +7,8 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "egl_gbm_backend.h"
#include "basiceglsurfacetexture_internal.h"
#include "basiceglsurfacetexture_wayland.h"
// kwin
#include "composite.h"
#include "drm_backend.h"
@ -605,9 +607,14 @@ bool EglGbmBackend::directScanoutActive(const Output &output)
return output.surfaceInterface != nullptr;
}
SceneOpenGLTexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGLTexture *texture)
PlatformSurfaceTexture *EglGbmBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return new EglGbmTexture(texture, this);
return new BasicEGLSurfaceTextureInternal(this, pixmap);
}
PlatformSurfaceTexture *EglGbmBackend::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return new BasicEGLSurfaceTextureWayland(this, pixmap);
}
void EglGbmBackend::setViewport(const Output &output) const
@ -783,15 +790,4 @@ bool EglGbmBackend::directScanoutAllowed(int screen) const
return !m_backend->usesSoftwareCursor() && !m_outputs[screen].output->directScanoutInhibited();
}
/************************************************
* EglTexture
************************************************/
EglGbmTexture::EglGbmTexture(KWin::SceneOpenGLTexture *texture, EglGbmBackend *backend)
: AbstractEglTexture(texture, backend)
{
}
EglGbmTexture::~EglGbmTexture() = default;
}

View file

@ -10,6 +10,8 @@
#define KWIN_EGL_GBM_BACKEND_H
#include "abstract_egl_drm_backend.h"
#include <kwinglutils.h>
#include <QSharedPointer>
struct gbm_surface;
@ -40,7 +42,9 @@ public:
EglGbmBackend(DrmBackend *drmBackend, DrmGpu *gpu);
~EglGbmBackend() override;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
void init() override;
@ -114,19 +118,6 @@ private:
friend class EglGbmTexture;
};
/**
* @brief Texture using an EGLImageKHR.
*/
class EglGbmTexture : public AbstractEglTexture
{
public:
~EglGbmTexture() override;
private:
friend class EglGbmBackend;
EglGbmTexture(SceneOpenGLTexture *texture, EglGbmBackend *backend);
};
} // namespace
#endif

View file

@ -85,9 +85,14 @@ void EglMultiBackend::doneCurrent()
m_backends[0]->doneCurrent();
}
SceneOpenGLTexturePrivate *EglMultiBackend::createBackendTexture(SceneOpenGLTexture *texture)
PlatformSurfaceTexture *EglMultiBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return m_backends[0]->createBackendTexture(texture);
return m_backends[0]->createPlatformSurfaceTextureInternal(pixmap);
}
PlatformSurfaceTexture *EglMultiBackend::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return m_backends[0]->createPlatformSurfaceTextureWayland(pixmap);
}
QSharedPointer<GLTexture> EglMultiBackend::textureForOutput(AbstractOutput *requestedOutput) const

View file

@ -31,7 +31,8 @@ public:
bool makeCurrent() override;
void doneCurrent() override;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QSharedPointer<GLTexture> textureForOutput(AbstractOutput *requestedOutput) const override;
void screenGeometryChanged(const QSize &size) override;
@ -49,7 +50,6 @@ private:
QVector<AbstractEglDrmBackend*> m_backends;
AbstractEglDrmBackend *findBackend(int screenId, int& internalScreenId) const;
};
}

View file

@ -7,6 +7,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "egl_stream_backend.h"
#include "basiceglsurfacetexture_internal.h"
#include "composite.h"
#include "drm_backend.h"
#include "drm_output.h"
@ -17,8 +18,10 @@
#include "renderloop_p.h"
#include "scene.h"
#include "screens.h"
#include "surfaceitem_wayland.h"
#include "wayland_server.h"
#include <kwinglplatform.h>
#include <kwingltexture.h>
#include <QOpenGLContext>
#include <KWaylandServer/buffer_interface.h>
#include <KWaylandServer/display.h>
@ -447,9 +450,14 @@ bool EglStreamBackend::presentOnOutput(EglStreamBackend::Output &o)
return o.output->present(o.buffer);
}
SceneOpenGLTexturePrivate *EglStreamBackend::createBackendTexture(SceneOpenGLTexture *texture)
PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return new EglStreamTexture(texture, this);
return new BasicEGLSurfaceTextureInternal(this, pixmap);
}
PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return new EglStreamSurfaceTextureWayland(this, pixmap);
}
QRegion EglStreamBackend::beginFrame(int screenId)
@ -486,18 +494,21 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con
* EglTexture
************************************************/
EglStreamTexture::EglStreamTexture(SceneOpenGLTexture *texture, EglStreamBackend *backend)
: AbstractEglTexture(texture, backend), m_backend(backend), m_fbo(0), m_rbo(0)
EglStreamSurfaceTextureWayland::EglStreamSurfaceTextureWayland(EglStreamBackend *backend,
SurfacePixmapWayland *pixmap)
: BasicEGLSurfaceTextureWayland(backend, pixmap)
, m_backend(backend)
{
}
EglStreamTexture::~EglStreamTexture()
EglStreamSurfaceTextureWayland::~EglStreamSurfaceTextureWayland()
{
glDeleteRenderbuffers(1, &m_rbo);
glDeleteFramebuffers(1, &m_fbo);
glDeleteTextures(1, &m_textureId);
}
bool EglStreamTexture::acquireStreamFrame(EGLStreamKHR stream)
bool EglStreamSurfaceTextureWayland::acquireStreamFrame(EGLStreamKHR stream)
{
EGLAttrib streamState;
if (!pEglQueryStreamAttribNV(m_backend->eglDisplay(), stream,
@ -519,7 +530,7 @@ bool EglStreamTexture::acquireStreamFrame(EGLStreamKHR stream)
return false;
}
void EglStreamTexture::createFbo()
void EglStreamSurfaceTextureWayland::createFbo()
{
glDeleteRenderbuffers(1, &m_rbo);
glDeleteFramebuffers(1, &m_fbo);
@ -528,7 +539,7 @@ void EglStreamTexture::createFbo()
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glGenRenderbuffers(1, &m_rbo);
glBindRenderbuffer(GL_RENDERBUFFER, m_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_size.width(), m_size.height());
glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_texture->width(), m_texture->height());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -536,11 +547,11 @@ void EglStreamTexture::createFbo()
// Renders the contents of the given EXTERNAL_OES texture
// to the scratch framebuffer, then copies this to m_texture
void EglStreamTexture::copyExternalTexture(GLuint tex)
void EglStreamSurfaceTextureWayland::copyExternalTexture(GLuint tex)
{
GLint oldViewport[4], oldProgram;
glGetIntegerv(GL_VIEWPORT, oldViewport);
glViewport(0, 0, m_size.width(), m_size.height());
glViewport(0, 0, m_texture->width(), m_texture->height());
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgram);
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
@ -561,7 +572,7 @@ void EglStreamTexture::copyExternalTexture(GLuint tex)
glEnd();
texture()->bind();
glCopyTexImage2D(m_target, 0, m_format, 0, 0, m_size.width(), m_size.height(), 0);
glCopyTexImage2D(m_texture->target(), 0, m_format, 0, 0, m_texture->width(), m_texture->height(), 0);
texture()->unbind();
glDisable(GL_TEXTURE_EXTERNAL_OES);
@ -572,10 +583,8 @@ void EglStreamTexture::copyExternalTexture(GLuint tex)
glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
}
bool EglStreamTexture::attachBuffer(KWaylandServer::BufferInterface *buffer)
bool EglStreamSurfaceTextureWayland::attachBuffer(KWaylandServer::BufferInterface *buffer)
{
QSize oldSize = m_size;
m_size = buffer->size();
GLenum oldFormat = m_format;
m_format = buffer->hasAlphaChannel() ? GL_RGBA : GL_RGB;
@ -584,23 +593,21 @@ bool EglStreamTexture::attachBuffer(KWaylandServer::BufferInterface *buffer)
yInverted = EGL_TRUE;
}
texture()->setYInverted(yInverted);
updateMatrix();
return oldSize != m_size ||
oldFormat != m_format ||
wasYInverted != texture()->isYInverted();
return oldFormat != m_format || wasYInverted != texture()->isYInverted();
}
bool EglStreamTexture::loadTexture(WindowPixmap *pixmap)
bool EglStreamSurfaceTextureWayland::create()
{
using namespace KWaylandServer;
SurfaceInterface *surface = pixmap->surface();
SurfaceInterface *surface = m_pixmap->surface();
const EglStreamBackend::StreamTexture *st = m_backend->lookupStreamTexture(surface);
if (pixmap->buffer() && st != nullptr) {
if (m_pixmap->buffer() && st != nullptr) {
glGenTextures(1, &m_texture);
texture()->setWrapMode(GL_CLAMP_TO_EDGE);
texture()->setFilter(GL_LINEAR);
glGenTextures(1, &m_textureId);
m_texture.reset(new GLTexture(m_textureId, 0, m_pixmap->buffer()->size()));
m_texture->setWrapMode(GL_CLAMP_TO_EDGE);
m_texture->setFilter(GL_LINEAR);
attachBuffer(surface->buffer());
createFbo();
@ -614,16 +621,16 @@ bool EglStreamTexture::loadTexture(WindowPixmap *pixmap)
return true;
} else {
// Not an EGLStream surface
return AbstractEglTexture::loadTexture(pixmap);
return BasicEGLSurfaceTextureWayland::create();
}
}
void EglStreamTexture::updateTexture(WindowPixmap *pixmap, const QRegion &region)
void EglStreamSurfaceTextureWayland::update(const QRegion &region)
{
using namespace KWaylandServer;
SurfaceInterface *surface = pixmap->surface();
SurfaceInterface *surface = m_pixmap->surface();
const EglStreamBackend::StreamTexture *st = m_backend->lookupStreamTexture(surface);
if (pixmap->buffer() && st != nullptr) {
if (m_pixmap->buffer() && st != nullptr) {
if (attachBuffer(surface->buffer())) {
createFbo();
@ -637,7 +644,7 @@ void EglStreamTexture::updateTexture(WindowPixmap *pixmap, const QRegion &region
}
} else {
// Not an EGLStream surface
AbstractEglTexture::updateTexture(pixmap, region);
BasicEGLSurfaceTextureWayland::update(region);
}
}

View file

@ -9,6 +9,7 @@
#ifndef KWIN_EGL_STREAM_BACKEND_H
#define KWIN_EGL_STREAM_BACKEND_H
#include "abstract_egl_drm_backend.h"
#include "basiceglsurfacetexture_wayland.h"
#include <KWaylandServer/surface_interface.h>
#include <KWaylandServer/eglstream_controller_interface.h>
#include <wayland-server-core.h>
@ -28,7 +29,8 @@ class EglStreamBackend : public AbstractEglDrmBackend
public:
EglStreamBackend(DrmBackend *b, DrmGpu *gpu);
~EglStreamBackend() override;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
void init() override;
@ -72,29 +74,27 @@ private:
KWaylandServer::EglStreamControllerInterface *m_eglStreamControllerInterface;
QHash<KWaylandServer::SurfaceInterface *, StreamTexture> m_streamTextures;
friend class EglStreamTexture;
friend class EglStreamSurfaceTextureWayland;
};
/**
* @brief External texture bound to an EGLStreamKHR.
*/
class EglStreamTexture : public AbstractEglTexture
class EglStreamSurfaceTextureWayland : public BasicEGLSurfaceTextureWayland
{
public:
~EglStreamTexture() override;
bool loadTexture(WindowPixmap *pixmap) override;
void updateTexture(WindowPixmap *pixmap, const QRegion &region) override;
EglStreamSurfaceTextureWayland(EglStreamBackend *backend, SurfacePixmapWayland *pixmap);
~EglStreamSurfaceTextureWayland() override;
bool create() override;
void update(const QRegion &region) override;
private:
EglStreamTexture(SceneOpenGLTexture *texture, EglStreamBackend *backend);
bool acquireStreamFrame(EGLStreamKHR stream);
void createFbo();
void copyExternalTexture(GLuint tex);
bool attachBuffer(KWaylandServer::BufferInterface *buffer);
EglStreamBackend *m_backend;
GLuint m_fbo, m_rbo;
GLuint m_fbo, m_rbo, m_textureId;
GLenum m_format;
friend class EglStreamBackend;
};
} // namespace

View file

@ -8,6 +8,8 @@
*/
#include "egl_gbm_backend.h"
// kwin
#include "basiceglsurfacetexture_internal.h"
#include "basiceglsurfacetexture_wayland.h"
#include "composite.h"
#include "virtual_backend.h"
#include "options.h"
@ -149,9 +151,14 @@ void EglGbmBackend::screenGeometryChanged(const QSize &size)
// TODO, create new buffer?
}
SceneOpenGLTexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGLTexture *texture)
PlatformSurfaceTexture *EglGbmBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return new EglGbmTexture(texture, this);
return new BasicEGLSurfaceTextureInternal(this, pixmap);
}
PlatformSurfaceTexture *EglGbmBackend::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return new BasicEGLSurfaceTextureWayland(this, pixmap);
}
QRegion EglGbmBackend::beginFrame(int screenId)
@ -214,15 +221,4 @@ void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion, const
eglSwapBuffers(eglDisplay(), surface());
}
/************************************************
* EglTexture
************************************************/
EglGbmTexture::EglGbmTexture(KWin::SceneOpenGLTexture *texture, EglGbmBackend *backend)
: AbstractEglTexture(texture, backend)
{
}
EglGbmTexture::~EglGbmTexture() = default;
} // namespace

View file

@ -25,7 +25,8 @@ public:
EglGbmBackend(VirtualBackend *b);
~EglGbmBackend() override;
void screenGeometryChanged(const QSize &size) override;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void init() override;
@ -38,20 +39,6 @@ private:
GLTexture *m_backBuffer = nullptr;
GLRenderTarget *m_fbo = nullptr;
int m_frameCounter = 0;
friend class EglGbmTexture;
};
/**
* @brief Texture using an EGLImageKHR.
*/
class EglGbmTexture : public AbstractEglTexture
{
public:
~EglGbmTexture() override;
private:
friend class EglGbmBackend;
EglGbmTexture(SceneOpenGLTexture *texture, EglGbmBackend *backend);
};
} // namespace

View file

@ -10,6 +10,8 @@
#define WL_EGL_PLATFORM 1
#include "egl_wayland_backend.h"
#include "basiceglsurfacetexture_internal.h"
#include "basiceglsurfacetexture_wayland.h"
#include "wayland_backend.h"
#include "wayland_output.h"
@ -348,9 +350,14 @@ void EglWaylandBackend::screenGeometryChanged(const QSize &size)
}
}
SceneOpenGLTexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGLTexture *texture)
PlatformSurfaceTexture *EglWaylandBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return new EglWaylandTexture(texture, this);
return new BasicEGLSurfaceTextureInternal(this, pixmap);
}
PlatformSurfaceTexture *EglWaylandBackend::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return new BasicEGLSurfaceTextureWayland(this, pixmap);
}
QRegion EglWaylandBackend::beginFrame(int screenId)
@ -391,16 +398,5 @@ void EglWaylandBackend::endFrame(int screenId, const QRegion &renderedRegion, co
}
}
/************************************************
* EglTexture
************************************************/
EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGLTexture *texture, KWin::Wayland::EglWaylandBackend *backend)
: AbstractEglTexture(texture, backend)
{
}
EglWaylandTexture::~EglWaylandTexture() = default;
}
}

View file

@ -67,8 +67,11 @@ class EglWaylandBackend : public AbstractEglBackend
public:
EglWaylandBackend(WaylandBackend *b);
~EglWaylandBackend() override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
void screenGeometryChanged(const QSize &size) override;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
void init() override;
@ -98,19 +101,6 @@ private:
friend class EglWaylandTexture;
};
/**
* @brief Texture using an EGLImageKHR.
*/
class EglWaylandTexture : public AbstractEglTexture
{
public:
~EglWaylandTexture() override;
private:
friend class EglWaylandBackend;
EglWaylandTexture(SceneOpenGLTexture *texture, EglWaylandBackend *backend);
};
}
}

View file

@ -7,6 +7,8 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "eglonxbackend.h"
// kwineffects
#include <kwinglutils.h>
// kwin
#include "main.h"
#include "options.h"

View file

@ -13,6 +13,7 @@
#include "scene.h"
#include "screens.h"
#include "softwarevsyncmonitor.h"
#include "surfaceitem_x11.h"
#include "x11_platform.h"
namespace KWin
@ -42,9 +43,9 @@ EglBackend::~EglBackend()
RenderLoopPrivate::get(kwinApp()->platform()->renderLoop())->invalidate();
}
SceneOpenGLTexturePrivate *EglBackend::createBackendTexture(SceneOpenGLTexture *texture)
PlatformSurfaceTexture *EglBackend::createPlatformSurfaceTextureX11(SurfacePixmapX11 *texture)
{
return new EglTexture(texture, this);
return new EglSurfaceTextureX11(this, texture);
}
void EglBackend::screenGeometryChanged(const QSize &size)
@ -114,21 +115,52 @@ void EglBackend::vblank(std::chrono::nanoseconds timestamp)
renderLoopPrivate->notifyFrameCompleted(timestamp);
}
/************************************************
* EglTexture
************************************************/
EglSurfaceTextureX11::EglSurfaceTextureX11(EglBackend *backend, SurfacePixmapX11 *texture)
: PlatformOpenGLSurfaceTextureX11(backend, texture)
{
}
EglTexture::EglTexture(KWin::SceneOpenGLTexture *texture, EglBackend *backend)
: AbstractEglTexture(texture, backend)
bool EglSurfaceTextureX11::create()
{
auto texture = new EglPixmapTexture(static_cast<EglBackend *>(m_backend));
texture->create(m_pixmap);
m_texture.reset(texture);
return !m_texture->isNull();
}
void EglSurfaceTextureX11::update(const QRegion &region)
{
Q_UNUSED(region)
// mipmaps need to be updated
m_texture->setDirty();
}
EglPixmapTexture::EglPixmapTexture(EglBackend *backend)
: GLTexture(*new EglPixmapTexturePrivate(this, backend))
{
}
bool EglPixmapTexture::create(SurfacePixmapX11 *texture)
{
Q_D(EglPixmapTexture);
return d->create(texture);
}
EglPixmapTexturePrivate::EglPixmapTexturePrivate(EglPixmapTexture *texture, EglBackend *backend)
: q(texture)
, m_backend(backend)
{
}
EglTexture::~EglTexture()
EglPixmapTexturePrivate::~EglPixmapTexturePrivate()
{
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
}
}
bool EglTexture::loadTexture(WindowPixmap *pixmap)
bool EglPixmapTexturePrivate::create(SurfacePixmapX11 *pixmap)
{
const xcb_pixmap_t nativePixmap = pixmap->pixmap();
if (nativePixmap == XCB_NONE) {
@ -136,7 +168,6 @@ bool EglTexture::loadTexture(WindowPixmap *pixmap)
}
glGenTextures(1, &m_texture);
auto q = texture();
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_LINEAR);
q->bind();
@ -144,30 +175,30 @@ bool EglTexture::loadTexture(WindowPixmap *pixmap)
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE
};
setImage(eglCreateImageKHR(m_backend->eglDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
(EGLClientBuffer)nativePixmap, attribs));
m_image = eglCreateImageKHR(m_backend->eglDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
reinterpret_cast<EGLClientBuffer>(nativePixmap), attribs);
if (EGL_NO_IMAGE_KHR == image()) {
if (EGL_NO_IMAGE_KHR == m_image) {
qCDebug(KWIN_CORE) << "failed to create egl image";
q->unbind();
q->discard();
return false;
}
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image());
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(m_image));
q->unbind();
q->setYInverted(true);
m_size = pixmap->toplevel()->bufferGeometry().size();
m_size = pixmap->size();
updateMatrix();
return true;
}
void EglTexture::onDamage()
void EglPixmapTexturePrivate::onDamage()
{
if (options->isGlStrictBinding()) {
// This is just implemented to be consistent with
// the example in mesa/demos/src/egl/opengles1/texture_from_pixmap.c
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) image());
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(m_image));
}
GLTexturePrivate::onDamage();
}

View file

@ -7,10 +7,15 @@
#pragma once
#include "eglonxbackend.h"
#include "platformopenglsurfacetexture_x11.h"
#include <kwingltexture.h>
#include <kwingltexture_p.h>
namespace KWin
{
class EglPixmapTexturePrivate;
class SoftwareVsyncMonitor;
class X11StandalonePlatform;
@ -22,7 +27,7 @@ public:
EglBackend(Display *display, X11StandalonePlatform *platform);
~EglBackend() override;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *texture) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
void screenGeometryChanged(const QSize &size) override;
@ -36,18 +41,41 @@ private:
int m_bufferAge = 0;
};
class EglTexture : public AbstractEglTexture
class EglPixmapTexture : public GLTexture
{
public:
~EglTexture() override;
explicit EglPixmapTexture(EglBackend *backend);
void onDamage() override;
bool loadTexture(WindowPixmap *pixmap) override;
bool create(SurfacePixmapX11 *texture);
private:
Q_DECLARE_PRIVATE(EglPixmapTexture)
};
class EglPixmapTexturePrivate : public GLTexturePrivate
{
public:
EglPixmapTexturePrivate(EglPixmapTexture *texture, EglBackend *backend);
~EglPixmapTexturePrivate() override;
bool create(SurfacePixmapX11 *texture);
protected:
void onDamage() override;
private:
friend class EglBackend;
EglTexture(SceneOpenGLTexture *texture, EglBackend *backend);
EglBackend *m_backend;
EglPixmapTexture *q;
EGLImageKHR m_image = EGL_NO_IMAGE_KHR;
};
class EglSurfaceTextureX11 : public PlatformOpenGLSurfaceTextureX11
{
public:
EglSurfaceTextureX11(EglBackend *backend, SurfacePixmapX11 *texture);
bool create() override;
void update(const QRegion &region) override;
};
} // namespace KWin

View file

@ -28,6 +28,7 @@
#include "renderloop_p.h"
#include "scene.h"
#include "screens.h"
#include "surfaceitem_x11.h"
#include "xcbutils.h"
// kwin libs
#include <kwinglplatform.h>
@ -722,9 +723,9 @@ void GlxBackend::screenGeometryChanged(const QSize &size)
m_bufferAge = 0;
}
SceneOpenGLTexturePrivate *GlxBackend::createBackendTexture(SceneOpenGLTexture *texture)
PlatformSurfaceTexture *GlxBackend::createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap)
{
return new GlxTexture(texture, this);
return new GlxSurfaceTextureX11(this, pixmap);
}
QRegion GlxBackend::beginFrame(int screenId)
@ -788,43 +789,71 @@ OverlayWindow* GlxBackend::overlayWindow() const
return m_overlayWindow;
}
/********************************************************
* GlxTexture
*******************************************************/
GlxTexture::GlxTexture(SceneOpenGLTexture *texture, GlxBackend *backend)
: SceneOpenGLTexturePrivate()
, q(texture)
, m_backend(backend)
, m_glxpixmap(None)
GlxSurfaceTextureX11::GlxSurfaceTextureX11(GlxBackend *backend, SurfacePixmapX11 *texture)
: PlatformOpenGLSurfaceTextureX11(backend, texture)
{
}
GlxTexture::~GlxTexture()
bool GlxSurfaceTextureX11::create()
{
if (m_glxpixmap != None) {
auto texture = new GlxPixmapTexture(static_cast<GlxBackend *>(m_backend));
texture->create(m_pixmap);
m_texture.reset(texture);
return !m_texture->isNull();
}
void GlxSurfaceTextureX11::update(const QRegion &region)
{
Q_UNUSED(region)
// mipmaps need to be updated
m_texture->setDirty();
}
GlxPixmapTexture::GlxPixmapTexture(GlxBackend *backend)
: GLTexture(*new GlxPixmapTexturePrivate(this, backend))
{
}
bool GlxPixmapTexture::create(SurfacePixmapX11 *texture)
{
Q_D(GlxPixmapTexture);
return d->create(texture);
}
GlxPixmapTexturePrivate::GlxPixmapTexturePrivate(GlxPixmapTexture *texture, GlxBackend *backend)
: m_backend(backend)
, q(texture)
, m_glxPixmap(None)
{
}
GlxPixmapTexturePrivate::~GlxPixmapTexturePrivate()
{
if (m_glxPixmap != None) {
if (!options->isGlStrictBinding()) {
glXReleaseTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT);
glXReleaseTexImageEXT(m_backend->display(), m_glxPixmap, GLX_FRONT_LEFT_EXT);
}
glXDestroyPixmap(display(), m_glxpixmap);
m_glxpixmap = None;
glXDestroyPixmap(m_backend->display(), m_glxPixmap);
m_glxPixmap = None;
}
}
void GlxTexture::onDamage()
void GlxPixmapTexturePrivate::onDamage()
{
if (options->isGlStrictBinding() && m_glxpixmap) {
glXReleaseTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT);
glXBindTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT, nullptr);
if (options->isGlStrictBinding() && m_glxPixmap) {
glXReleaseTexImageEXT(m_backend->display(), m_glxPixmap, GLX_FRONT_LEFT_EXT);
glXBindTexImageEXT(m_backend->display(), m_glxPixmap, GLX_FRONT_LEFT_EXT, nullptr);
}
GLTexturePrivate::onDamage();
}
bool GlxTexture::loadTexture(xcb_pixmap_t pixmap, const QSize &size, xcb_visualid_t visual)
bool GlxPixmapTexturePrivate::create(SurfacePixmapX11 *texture)
{
if (pixmap == XCB_NONE || size.isEmpty() || visual == XCB_NONE)
if (texture->pixmap() == XCB_NONE || texture->size().isEmpty() || texture->visual() == XCB_NONE)
return false;
const FBConfigInfo *info = m_backend->infoForVisual(visual);
const FBConfigInfo *info = m_backend->infoForVisual(texture->visual());
if (!info || info->fbconfig == nullptr)
return false;
@ -847,8 +876,8 @@ bool GlxTexture::loadTexture(xcb_pixmap_t pixmap, const QSize &size, xcb_visuali
0
};
m_glxpixmap = glXCreatePixmap(display(), info->fbconfig, pixmap, attrs);
m_size = size;
m_glxPixmap = glXCreatePixmap(m_backend->display(), info->fbconfig, texture->pixmap(), attrs);
m_size = texture->size();
m_yInverted = info->y_inverted ? true : false;
m_canUseMipmaps = false;
@ -858,21 +887,10 @@ bool GlxTexture::loadTexture(xcb_pixmap_t pixmap, const QSize &size, xcb_visuali
q->setFilter(GL_NEAREST);
glBindTexture(m_target, m_texture);
glXBindTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT, nullptr);
glXBindTexImageEXT(m_backend->display(), m_glxPixmap, GLX_FRONT_LEFT_EXT, nullptr);
updateMatrix();
return true;
}
bool GlxTexture::loadTexture(WindowPixmap *pixmap)
{
Toplevel *t = pixmap->toplevel();
return loadTexture(pixmap->pixmap(), t->bufferGeometry().size(), t->visual());
}
OpenGLBackend *GlxTexture::backend()
{
return m_backend;
}
} // namespace

View file

@ -9,16 +9,24 @@
#ifndef KWIN_GLX_BACKEND_H
#define KWIN_GLX_BACKEND_H
#include "openglbackend.h"
#include "texture.h"
#include "platformopenglsurfacetexture_x11.h"
#include "x11eventfilter.h"
#include <xcb/glx.h>
#include <epoxy/glx.h>
#include <fixx11h.h>
#include <kwingltexture.h>
#include <kwingltexture_p.h>
#include <QHash>
#include <memory>
namespace KWin
{
class GlxPixmapTexturePrivate;
class VsyncMonitor;
class X11StandalonePlatform;
@ -63,7 +71,7 @@ public:
GlxBackend(Display *display, X11StandalonePlatform *backend);
~GlxBackend() override;
void screenGeometryChanged(const QSize &size) override;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
bool makeCurrent() override;
@ -71,6 +79,8 @@ public:
OverlayWindow* overlayWindow() const override;
void init() override;
Display *display() const { return m_x11Display; }
private:
void vblank(std::chrono::nanoseconds timestamp);
void present(const QRegion &damage);
@ -81,9 +91,6 @@ private:
bool initFbConfig();
void initVisualDepthHashTable();
void setSwapInterval(int interval);
Display *display() const {
return m_x11Display;
}
int visualDepth(xcb_visualid_t visual) const;
FBConfigInfo *infoForVisual(xcb_visualid_t visual);
@ -107,30 +114,44 @@ private:
Display *m_x11Display;
X11StandalonePlatform *m_backend;
VsyncMonitor *m_vsyncMonitor = nullptr;
friend class GlxTexture;
friend class GlxPixmapTexturePrivate;
};
/**
* @brief Texture using an GLXPixmap.
*/
class GlxTexture : public SceneOpenGLTexturePrivate
class GlxPixmapTexture final : public GLTexture
{
public:
~GlxTexture() override;
void onDamage() override;
bool loadTexture(WindowPixmap *pixmap) override;
OpenGLBackend *backend() override;
explicit GlxPixmapTexture(GlxBackend *backend);
bool create(SurfacePixmapX11 *texture);
private:
Q_DECLARE_PRIVATE(GlxPixmapTexture)
};
class GlxPixmapTexturePrivate final : public GLTexturePrivate
{
public:
GlxPixmapTexturePrivate(GlxPixmapTexture *texture, GlxBackend *backend);
~GlxPixmapTexturePrivate() override;
bool create(SurfacePixmapX11 *texture);
protected:
void onDamage() override;
private:
friend class GlxBackend;
GlxTexture(SceneOpenGLTexture *texture, GlxBackend *backend);
bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual);
Display *display() const {
return m_backend->m_x11Display;
}
SceneOpenGLTexture *q;
GlxBackend *m_backend;
GLXPixmap m_glxpixmap; // the glx pixmap the texture is bound to
GlxPixmapTexture *q;
GLXPixmap m_glxPixmap;
};
class GlxSurfaceTextureX11 final : public PlatformOpenGLSurfaceTextureX11
{
public:
GlxSurfaceTextureX11(GlxBackend *backend, SurfacePixmapX11 *pixmap);
bool create() override;
void update(const QRegion &region) override;
};
} // namespace

View file

@ -8,6 +8,8 @@
*/
#include "egl_x11_backend.h"
// kwin
#include "basiceglsurfacetexture_internal.h"
#include "basiceglsurfacetexture_wayland.h"
#include "main.h"
#include "screens.h"
#include "softwarevsyncmonitor.h"
@ -106,27 +108,19 @@ void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, co
}
}
SceneOpenGLTexturePrivate *EglX11Backend::createBackendTexture(SceneOpenGLTexture *texture)
{
return new EglX11Texture(texture, this);
}
void EglX11Backend::screenGeometryChanged(const QSize &size)
{
Q_UNUSED(size)
}
/************************************************
* EglX11Texture
************************************************/
EglX11Texture::EglX11Texture(KWin::SceneOpenGLTexture *texture, EglX11Backend *backend)
: AbstractEglTexture(texture, backend)
PlatformSurfaceTexture *EglX11Backend::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return new BasicEGLSurfaceTextureWayland(this, pixmap);
}
EglX11Texture::~EglX11Texture()
PlatformSurfaceTexture *EglX11Backend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return new BasicEGLSurfaceTextureInternal(this, pixmap);
}
} // namespace

View file

@ -24,7 +24,8 @@ public:
explicit EglX11Backend(X11WindowedBackend *backend);
~EglX11Backend() override;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
void init() override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) override;
@ -42,19 +43,6 @@ private:
X11WindowedBackend *m_backend;
};
/**
* @brief Texture using an EGLImageKHR.
*/
class EglX11Texture : public AbstractEglTexture
{
public:
~EglX11Texture() override;
private:
friend class EglX11Backend;
EglX11Texture(SceneOpenGLTexture *texture, EglX11Backend *backend);
};
} // namespace
#endif

View file

@ -17,7 +17,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "scene_opengl.h"
#include "texture.h"
#include "platformopenglsurfacetexture.h"
#include "platform.h"
#include "wayland_server.h"
@ -657,7 +657,7 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
break;
}
SurfaceItem *topMost = findTopMostSurface(window->surfaceItem());
auto pixmap = topMost->windowPixmap();
auto pixmap = topMost->pixmap();
if (!pixmap) {
break;
}
@ -810,11 +810,6 @@ void SceneOpenGL::extendPaintRegion(QRegion &region, bool opaqueFullscreen)
}
}
SceneOpenGLTexture *SceneOpenGL::createTexture()
{
return new SceneOpenGLTexture(m_backend);
}
bool SceneOpenGL::viewportLimitsMatched(const QSize &size) const {
if (kwinApp()->operationMode() != Application::OperationModeX11) {
// TODO: On Wayland we can't suspend. Find a solution that works here as well!
@ -926,6 +921,21 @@ QSharedPointer<GLTexture> SceneOpenGL::textureForOutput(AbstractOutput* output)
return m_backend->textureForOutput(output);
}
PlatformSurfaceTexture *SceneOpenGL::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return m_backend->createPlatformSurfaceTextureInternal(pixmap);
}
PlatformSurfaceTexture *SceneOpenGL::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return m_backend->createPlatformSurfaceTextureWayland(pixmap);
}
PlatformSurfaceTexture *SceneOpenGL::createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap)
{
return m_backend->createPlatformSurfaceTextureX11(pixmap);
}
//****************************************
// SceneOpenGL2
//****************************************
@ -1223,11 +1233,6 @@ GLTexture *OpenGLWindow::getDecorationTexture() const
return nullptr;
}
WindowPixmap *OpenGLWindow::createWindowPixmap()
{
return new OpenGLWindowPixmap(this, m_scene);
}
QVector4D OpenGLWindow::modulate(float opacity, float brightness) const
{
const float a = opacity;
@ -1265,16 +1270,34 @@ static int countChildren(Item *root)
static bool bindSurfaceTexture(SurfaceItem *surfaceItem)
{
auto pixmap = static_cast<OpenGLWindowPixmap *>(surfaceItem->windowPixmap());
if (!pixmap) {
SurfacePixmap *surfacePixmap = surfaceItem->pixmap();
if (!surfacePixmap) {
return false;
}
if (pixmap->isDiscarded()) {
return !pixmap->texture()->isNull();
auto platformSurfaceTexture =
static_cast<PlatformOpenGLSurfaceTexture *>(surfacePixmap->platformTexture());
if (surfacePixmap->isDiscarded()) {
return platformSurfaceTexture->texture();
}
if (!pixmap->bind(surfaceItem->damage())) {
if (platformSurfaceTexture->texture()) {
const QRegion region = surfaceItem->damage();
if (!region.isEmpty()) {
platformSurfaceTexture->update(region);
}
surfaceItem->resetDamage();
return true;
}
if (!surfacePixmap->isValid()) {
return false;
}
if (!platformSurfaceTexture->create()) {
qCDebug(KWIN_OPENGL) << "Failed to bind window";
return false;
}
surfaceItem->resetDamage();
return true;
}
@ -1356,11 +1379,13 @@ void OpenGLWindow::initializeRenderContext(RenderContext &context, const WindowP
break;
}
auto windowPixmap = static_cast<OpenGLWindowPixmap *>(item->windowPixmap());
const SurfacePixmap *surfaceTexture = item->pixmap();
const PlatformOpenGLSurfaceTexture *platformSurfaceTexture =
static_cast<PlatformOpenGLSurfaceTexture *>(surfaceTexture->platformTexture());
RenderNode &contentRenderNode = renderNodes[context.contentOffset + i++];
contentRenderNode.texture = windowPixmap->texture();
contentRenderNode.hasAlpha = windowPixmap->hasAlphaChannel();
contentRenderNode.texture = platformSurfaceTexture->texture();
contentRenderNode.hasAlpha = surfaceTexture->hasAlphaChannel();
contentRenderNode.opacity = contentOpacity;
contentRenderNode.coordinateType = UnnormalizedCoordinates;
contentRenderNode.leafType = ContentLeaf;
@ -1375,9 +1400,8 @@ void OpenGLWindow::initializeRenderContext(RenderContext &context, const WindowP
// work on Wayland, we have to render the current and the previous window pixmap trees in
// offscreen render targets, then use a cross-fading shader to blend those two layers.
if (data.crossFadeProgress() != 1.0) {
OpenGLWindowPixmap *previous =
static_cast<OpenGLWindowPixmap *>(surfaceItem()->previousWindowPixmap());
if (previous) { // TODO(vlad): Should cross-fading be disabled on Wayland?
const SurfacePixmap *previous = surfaceItem()->previousPixmap();
if (previous && previous->isValid()) { // TODO(vlad): Should cross-fading be disabled on Wayland?
const QRect &oldGeometry = previous->contentsRect();
RenderNode &previousContentRenderNode = renderNodes[context.previousContentOffset];
for (const WindowQuad &quad : qAsConst(renderNodes[context.contentOffset].quads)) {
@ -1402,7 +1426,10 @@ void OpenGLWindow::initializeRenderContext(RenderContext &context, const WindowP
previousContentRenderNode.quads.append(newQuad);
}
previousContentRenderNode.texture = previous->texture();
const auto previousPlatformTexture =
static_cast<PlatformOpenGLSurfaceTexture *>(previous->platformTexture());
previousContentRenderNode.texture = previousPlatformTexture->texture();
previousContentRenderNode.hasAlpha = previous->hasAlphaChannel();
previousContentRenderNode.opacity = data.opacity() * (1.0 - data.crossFadeProgress());
previousContentRenderNode.coordinateType = NormalizedCoordinates;
@ -1570,11 +1597,11 @@ void OpenGLWindow::performPaint(int mask, const QRegion &region, const WindowPai
QSharedPointer<GLTexture> OpenGLWindow::windowTexture()
{
OpenGLWindowPixmap *frame = nullptr;
PlatformOpenGLSurfaceTexture *frame = nullptr;
const SurfaceItem *item = surfaceItem();
if (item) {
frame = static_cast<OpenGLWindowPixmap *>(item->windowPixmap());
frame = static_cast<PlatformOpenGLSurfaceTexture *>(item->pixmap()->platformTexture());
}
if (frame && item->childItems().isEmpty()) {
@ -1606,50 +1633,6 @@ QSharedPointer<GLTexture> OpenGLWindow::windowTexture()
}
}
//****************************************
// OpenGLWindowPixmap
//****************************************
OpenGLWindowPixmap::OpenGLWindowPixmap(Scene::Window *window, SceneOpenGL* scene)
: WindowPixmap(window)
, m_texture(scene->createTexture())
{
}
OpenGLWindowPixmap::~OpenGLWindowPixmap()
{
}
bool OpenGLWindowPixmap::bind(const QRegion &region)
{
if (!m_texture->isNull()) {
if (!region.isEmpty()) {
m_texture->updateFromPixmap(this, region);
// mipmaps need to be updated
m_texture->setDirty();
}
return true;
}
if (!isValid()) {
return false;
}
if (!m_texture->load(this)) {
qCDebug(KWIN_OPENGL) << "Failed to bind window";
return false;
}
return true;
}
bool OpenGLWindowPixmap::isValid() const
{
if (!m_texture->isNull()) {
return true;
}
return WindowPixmap::isValid();
}
//****************************************
// SceneOpenGL::EffectFrame
//****************************************

View file

@ -49,19 +49,15 @@ public:
void triggerFence() override;
virtual QMatrix4x4 projectionMatrix() const = 0;
bool animationsSupported() const override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
void insertWait();
bool debug() const { return m_debug; }
void initDebugOutput();
/**
* @brief Factory method to create a backend specific texture.
*
* @return :SceneOpenGL::Texture*
*/
SceneOpenGLTexture *createTexture();
OpenGLBackend *backend() const {
return m_backend;
}
@ -134,8 +130,6 @@ private:
GLuint vao;
};
class OpenGLWindowPixmap;
class OpenGLWindow final : public Scene::Window
{
Q_OBJECT
@ -183,7 +177,6 @@ public:
OpenGLWindow(Toplevel *toplevel, SceneOpenGL *scene);
~OpenGLWindow() override;
WindowPixmap *createWindowPixmap() override;
void performPaint(int mask, const QRegion &region, const WindowPaintData &data) override;
QSharedPointer<GLTexture> windowTexture() override;
@ -202,18 +195,6 @@ private:
bool m_blendingEnabled = false;
};
class OpenGLWindowPixmap : public WindowPixmap
{
public:
explicit OpenGLWindowPixmap(Scene::Window *window, SceneOpenGL *scene);
~OpenGLWindowPixmap() override;
SceneOpenGLTexture *texture() const;
bool bind(const QRegion &region);
bool isValid() const override;
private:
QScopedPointer<SceneOpenGLTexture> m_texture;
};
class SceneOpenGL::EffectFrame
: public Scene::EffectFrame
{
@ -304,11 +285,6 @@ private:
QScopedPointer<GLTexture> m_texture;
};
inline SceneOpenGLTexture* OpenGLWindowPixmap::texture() const
{
return m_texture.data();
}
class KWIN_EXPORT OpenGLFactory : public SceneFactory
{
Q_OBJECT

View file

@ -7,6 +7,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "scene_qpainter.h"
#include "platformqpaintersurfacetexture.h"
// KWin
#include "abstract_client.h"
#include "composite.h"
@ -251,12 +252,18 @@ void SceneQPainter::Window::performPaint(int mask, const QRegion &_region, const
void SceneQPainter::Window::renderSurfaceItem(QPainter *painter, SurfaceItem *surfaceItem)
{
QPainterWindowPixmap *windowPixmap =
static_cast<QPainterWindowPixmap *>(surfaceItem->windowPixmap());
if (!windowPixmap || !windowPixmap->isValid()) {
const SurfacePixmap *surfaceTexture = surfaceItem->pixmap();
if (!surfaceTexture || !surfaceTexture->isValid()) {
return;
}
PlatformQPainterSurfaceTexture *platformSurfaceTexture =
static_cast<PlatformQPainterSurfaceTexture *>(surfaceTexture->platformTexture());
if (!platformSurfaceTexture->isValid()) {
platformSurfaceTexture->create();
} else {
platformSurfaceTexture->update(surfaceItem->damage());
}
surfaceItem->resetDamage();
const QRegion shape = surfaceItem->shape();
@ -268,7 +275,7 @@ void SceneQPainter::Window::renderSurfaceItem(QPainter *painter, SurfaceItem *su
const QPointF bufferBottomRight = surfaceItem->mapToBuffer(rect.bottomRight());
painter->drawImage(QRectF(windowTopLeft, windowBottomRight),
windowPixmap->image(),
platformSurfaceTexture->image(),
QRectF(bufferTopLeft, bufferBottomRight));
}
@ -332,73 +339,19 @@ void SceneQPainter::Window::renderWindowDecorations(QPainter *painter)
painter->drawImage(dbr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Bottom));
}
WindowPixmap *SceneQPainter::Window::createWindowPixmap()
{
return new QPainterWindowPixmap(this);
}
Decoration::Renderer *SceneQPainter::createDecorationRenderer(Decoration::DecoratedClientImpl *impl)
{
return new SceneQPainterDecorationRenderer(impl);
}
//****************************************
// QPainterWindowPixmap
//****************************************
QPainterWindowPixmap::QPainterWindowPixmap(Scene::Window *window)
: WindowPixmap(window)
PlatformSurfaceTexture *SceneQPainter::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return m_backend->createPlatformSurfaceTextureInternal(pixmap);
}
QPainterWindowPixmap::~QPainterWindowPixmap()
PlatformSurfaceTexture *SceneQPainter::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
}
void QPainterWindowPixmap::create()
{
if (isValid()) {
return;
}
KWin::WindowPixmap::create();
if (!isValid()) {
return;
}
if (!surface()) {
// That's an internal client.
m_image = internalImage();
return;
}
// performing deep copy, this could probably be improved
m_image = buffer()->data().copy();
}
void QPainterWindowPixmap::update()
{
const auto oldBuffer = buffer();
WindowPixmap::update();
const auto &b = buffer();
if (!surface()) {
// That's an internal client.
m_image = internalImage();
return;
}
if (!b) {
m_image = QImage();
return;
}
if (b == oldBuffer) {
return;
}
// perform deep copy
m_image = b->data().copy();
}
bool QPainterWindowPixmap::isValid() const
{
if (!m_image.isNull()) {
return true;
}
return WindowPixmap::isValid();
return m_backend->createPlatformSurfaceTextureWayland(pixmap);
}
QPainterEffectFrame::QPainterEffectFrame(EffectFrameImpl *frame, SceneQPainter *scene)

View file

@ -34,6 +34,8 @@ public:
Shadow *createShadow(Toplevel *toplevel) override;
Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override;
void screenGeometryChanged(const QSize &size) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
bool animationsSupported() const override {
return false;
@ -61,21 +63,6 @@ private:
class Window;
};
class QPainterWindowPixmap : public WindowPixmap
{
public:
explicit QPainterWindowPixmap(Scene::Window *window);
~QPainterWindowPixmap() override;
void create() override;
void update() override;
bool isValid() const override;
const QImage &image();
private:
QImage m_image;
};
class SceneQPainter::Window : public Scene::Window
{
Q_OBJECT
@ -84,8 +71,6 @@ public:
Window(SceneQPainter *scene, Toplevel *c);
~Window() override;
void performPaint(int mask, const QRegion &region, const WindowPaintData &data) override;
protected:
WindowPixmap *createWindowPixmap() override;
private:
void renderSurfaceItem(QPainter *painter, SurfaceItem *surfaceItem);
void renderShadow(QPainter *painter);
@ -176,12 +161,6 @@ QPainter* SceneQPainter::scenePainter() const
return m_painter.data();
}
inline
const QImage &QPainterWindowPixmap::image()
{
return m_image;
}
} // KWin
#endif // KWIN_SCENEQPAINTER_H

View file

@ -9,6 +9,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "scene_xrender.h"
#include "platformxrendersurfacetexture_x11.h"
#include "utils.h"
#include "xrenderbackend.h"
@ -26,7 +27,7 @@
#include "renderloop.h"
#include "screens.h"
#include "shadowitem.h"
#include "surfaceitem.h"
#include "surfaceitem_x11.h"
#include "xcbutils.h"
#include "decorations/decoratedclient.h"
@ -139,6 +140,11 @@ Decoration::Renderer *SceneXrender::createDecorationRenderer(Decoration::Decorat
return new SceneXRenderDecorationRenderer(client);
}
PlatformSurfaceTexture *SceneXrender::createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap)
{
return new PlatformXrenderSurfaceTextureX11(pixmap);
}
//****************************************
// SceneXrender::Window
//****************************************
@ -150,7 +156,6 @@ XRenderPicture *SceneXrender::Window::s_fadeAlphaPicture = nullptr;
SceneXrender::Window::Window(Toplevel* c, SceneXrender *scene)
: Scene::Window(c)
, m_scene(scene)
, format(XRenderUtils::findPictFormat(c->visual()))
{
}
@ -267,11 +272,20 @@ void SceneXrender::Window::performPaint(int mask, const QRegion &_region, const
if (region.isEmpty())
return;
XRenderWindowPixmap *pixmap = static_cast<XRenderWindowPixmap *>(surfaceItem()->windowPixmap());
if (!pixmap || !pixmap->isValid()) {
SurfacePixmap *surfaceTexture = surfaceItem()->pixmap();
if (!surfaceTexture || !surfaceTexture->isValid()) {
return;
}
xcb_render_picture_t pic = pixmap->picture();
PlatformXrenderSurfaceTextureX11 *platformSurfaceTexture =
static_cast<PlatformXrenderSurfaceTextureX11 *>(surfaceTexture->platformTexture());
if (platformSurfaceTexture->picture() == XCB_RENDER_PICTURE_NONE) {
if (!platformSurfaceTexture->create()) {
qCWarning(KWIN_XRENDER, "Failed to create platform surface texture for window 0x%x",
window()->frameId());
return;
}
}
xcb_render_picture_t pic = platformSurfaceTexture->picture();
if (pic == XCB_RENDER_PICTURE_NONE) // The render format can be null for GL and/or Xv visuals
return;
surfaceItem()->resetDamage();
@ -503,9 +517,11 @@ xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, m_xrenderShadow->pic
xcb_render_composite(connection(), clientRenderOp, pic, clientAlpha, renderTarget,
cr.x(), cr.y(), 0, 0, dr.x(), dr.y(), dr.width(), dr.height());
if (data.crossFadeProgress() < 1.0 && data.crossFadeProgress() > 0.0) {
XRenderWindowPixmap *previous =
static_cast<XRenderWindowPixmap *>(surfaceItem()->previousWindowPixmap());
if (previous && previous != pixmap) {
SurfacePixmap *previous = surfaceItem()->previousPixmap();
if (previous && previous != surfaceTexture) {
auto previousPlatformTexture =
static_cast<PlatformXrenderSurfaceTextureX11 *>(previous->platformTexture());
static xcb_render_color_t cFadeColor = {0, 0, 0, 0};
cFadeColor.alpha = uint16_t((1.0 - data.crossFadeProgress()) * 0xffff);
if (!s_fadeAlphaPicture) {
@ -514,21 +530,24 @@ xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, m_xrenderShadow->pic
xcb_rectangle_t rect = {0, 0, 1, 1};
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, *s_fadeAlphaPicture, cFadeColor , 1, &rect);
}
if (previous->size() != pixmap->size()) {
if (previous->size() != surfaceTexture->size()) {
xcb_render_transform_t xform2 = {
DOUBLE_TO_FIXED(FIXED_TO_DOUBLE(xform.matrix11) * previous->size().width() / pixmap->size().width()), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0),
DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(FIXED_TO_DOUBLE(xform.matrix22) * previous->size().height() / pixmap->size().height()), DOUBLE_TO_FIXED(0),
DOUBLE_TO_FIXED(FIXED_TO_DOUBLE(xform.matrix11) * previous->size().width() / surfaceTexture->size().width()), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0),
DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(FIXED_TO_DOUBLE(xform.matrix22) * previous->size().height() / surfaceTexture->size().height()), DOUBLE_TO_FIXED(0),
DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(1)
};
xcb_render_set_picture_transform(connection(), previous->picture(), xform2);
xcb_render_set_picture_transform(connection(), previousPlatformTexture->picture(), xform2);
}
xcb_render_composite(connection(), opaque ? XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_ATOP,
previous->picture(), *s_fadeAlphaPicture, renderTarget,
previousPlatformTexture->picture(), *s_fadeAlphaPicture,
renderTarget,
cr.x(), cr.y(), 0, 0, dr.x(), dr.y(), dr.width(), dr.height());
if (previous->size() != pixmap->size()) {
xcb_render_set_picture_transform(connection(), previous->picture(), identity);
if (previous->size() != surfaceTexture->size()) {
xcb_render_set_picture_transform(connection(),
previousPlatformTexture->picture(),
identity);
}
}
}
@ -609,11 +628,6 @@ void SceneXrender::Window::setPictureFilter(xcb_render_picture_t pic, Scene::Ima
xcb_render_set_picture_filter(connection(), pic, filterName.length(), filterName.constData(), 0, nullptr);
}
WindowPixmap* SceneXrender::Window::createWindowPixmap()
{
return new XRenderWindowPixmap(this, format);
}
void SceneXrender::screenGeometryChanged(const QSize &size)
{
Scene::screenGeometryChanged(size);
@ -630,37 +644,6 @@ OverlayWindow *SceneXrender::overlayWindow() const
return m_backend->overlayWindow();
}
//****************************************
// XRenderWindowPixmap
//****************************************
XRenderWindowPixmap::XRenderWindowPixmap(Scene::Window *window, xcb_render_pictformat_t format)
: WindowPixmap(window)
, m_picture(XCB_RENDER_PICTURE_NONE)
, m_format(format)
{
}
XRenderWindowPixmap::~XRenderWindowPixmap()
{
if (m_picture != XCB_RENDER_PICTURE_NONE) {
xcb_render_free_picture(connection(), m_picture);
}
}
void XRenderWindowPixmap::create()
{
if (isValid()) {
return;
}
KWin::WindowPixmap::create();
if (!isValid()) {
return;
}
m_picture = xcb_generate_id(connection());
xcb_render_create_picture(connection(), m_picture, pixmap(), m_format, 0, nullptr);
}
//****************************************
// SceneXrender::EffectFrame
//****************************************

View file

@ -40,6 +40,7 @@ public:
xcb_render_picture_t xrenderBufferPicture() const override;
OverlayWindow *overlayWindow() const override;
Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *client) override;
PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
bool animationsSupported() const override {
return true;
@ -71,8 +72,6 @@ public:
QRegion transformedShape() const;
void setTransformedShape(const QRegion& shape);
static void cleanup();
protected:
WindowPixmap* createWindowPixmap() override;
private:
QRect mapToScreen(int mask, const WindowPaintData &data, const QRect &rect) const;
QPoint mapToScreen(int mask, const WindowPaintData &data, const QPoint &point) const;
@ -81,25 +80,12 @@ private:
void prepareTempPixmap();
void setPictureFilter(xcb_render_picture_t pic, ImageFilterType filter);
SceneXrender *m_scene;
xcb_render_pictformat_t format;
QRegion transformed_shape;
static QRect temp_visibleRect;
static XRenderPicture *s_tempPicture;
static XRenderPicture *s_fadeAlphaPicture;
};
class XRenderWindowPixmap : public WindowPixmap
{
public:
explicit XRenderWindowPixmap(Scene::Window *window, xcb_render_pictformat_t format);
~XRenderWindowPixmap() override;
xcb_render_picture_t picture() const;
void create() override;
private:
xcb_render_picture_t m_picture;
xcb_render_pictformat_t m_format;
};
class SceneXrender::EffectFrame
: public Scene::EffectFrame
{
@ -140,12 +126,6 @@ void SceneXrender::Window::setTransformedShape(const QRegion& shape)
transformed_shape = shape;
}
inline
xcb_render_picture_t XRenderWindowPixmap::picture() const
{
return m_picture;
}
/**
* @short XRender implementation of Shadow.
*

View file

@ -726,6 +726,24 @@ QVector<QByteArray> Scene::openGLPlatformInterfaceExtensions() const
return QVector<QByteArray>{};
}
PlatformSurfaceTexture *Scene::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
Q_UNUSED(pixmap)
return nullptr;
}
PlatformSurfaceTexture *Scene::createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap)
{
Q_UNUSED(pixmap)
return nullptr;
}
PlatformSurfaceTexture *Scene::createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
Q_UNUSED(pixmap)
return nullptr;
}
//****************************************
// Scene::Window
//****************************************
@ -1186,125 +1204,6 @@ void Scene::Window::updateWindowPosition()
m_windowItem->setPosition(pos());
}
//****************************************
// WindowPixmap
//****************************************
WindowPixmap::WindowPixmap(Scene::Window *window)
: m_window(window)
, m_pixmap(XCB_PIXMAP_NONE)
, m_discarded(false)
{
}
WindowPixmap::~WindowPixmap()
{
if (m_pixmap != XCB_WINDOW_NONE) {
xcb_free_pixmap(connection(), m_pixmap);
}
clear();
}
void WindowPixmap::create()
{
if (isValid() || toplevel()->isDeleted()) {
return;
}
// always update from Buffer on Wayland, don't try using XPixmap
if (kwinApp()->shouldUseWaylandForCompositing()) {
// use Buffer
update();
return;
}
XServerGrabber grabber;
xcb_pixmap_t pix = xcb_generate_id(connection());
xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection(), toplevel()->frameId(), pix);
Xcb::WindowAttributes windowAttributes(toplevel()->frameId());
Xcb::WindowGeometry windowGeometry(toplevel()->frameId());
if (xcb_generic_error_t *error = xcb_request_check(connection(), namePixmapCookie)) {
qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x (error code %d)",
toplevel()->window(), error->error_code);
free(error);
return;
}
// check that the received pixmap is valid and actually matches what we
// know about the window (i.e. size)
if (!windowAttributes || windowAttributes->map_state != XCB_MAP_STATE_VIEWABLE) {
qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x (not viewable)",
toplevel()->window());
xcb_free_pixmap(connection(), pix);
return;
}
const QRect bufferGeometry = toplevel()->bufferGeometry();
if (windowGeometry.size() != bufferGeometry.size()) {
qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x (mismatched geometry)",
toplevel()->window());
xcb_free_pixmap(connection(), pix);
return;
}
m_pixmap = pix;
m_pixmapSize = bufferGeometry.size();
m_contentsRect = QRect(toplevel()->clientPos(), toplevel()->clientSize());
}
void WindowPixmap::clear()
{
setBuffer(nullptr);
}
void WindowPixmap::setBuffer(KWaylandServer::BufferInterface *buffer)
{
if (buffer == m_buffer) {
return;
}
if (m_buffer) {
disconnect(m_buffer, &KWaylandServer::BufferInterface::aboutToBeDestroyed, this, &WindowPixmap::clear);
m_buffer->unref();
}
m_buffer = buffer;
if (m_buffer) {
m_buffer->ref();
connect(m_buffer, &KWaylandServer::BufferInterface::aboutToBeDestroyed, this, &WindowPixmap::clear);
}
}
void WindowPixmap::update()
{
if (KWaylandServer::SurfaceInterface *s = surface()) {
setBuffer(s->buffer());
} else if (toplevel()->internalFramebufferObject()) {
m_fbo = toplevel()->internalFramebufferObject();
} else if (!toplevel()->internalImageObject().isNull()) {
m_internalImage = toplevel()->internalImageObject();
} else {
clear();
}
}
bool WindowPixmap::isValid() const
{
if (m_buffer || !m_fbo.isNull() || !m_internalImage.isNull()) {
return true;
}
return m_pixmap != XCB_PIXMAP_NONE;
}
KWaylandServer::SurfaceInterface *WindowPixmap::surface() const
{
return m_surface;
}
void WindowPixmap::setSurface(KWaylandServer::SurfaceInterface *surface)
{
m_surface = surface;
}
bool WindowPixmap::hasAlphaChannel() const
{
if (buffer())
return buffer()->hasAlphaChannel();
return toplevel()->hasAlpha();
}
//****************************************
// Scene::EffectFrame
//****************************************

View file

@ -43,12 +43,15 @@ class EffectWindowImpl;
class GLTexture;
class Item;
class OverlayWindow;
class PlatformSurfaceTexture;
class RenderLoop;
class Shadow;
class ShadowItem;
class SurfaceItem;
class SurfacePixmapInternal;
class SurfacePixmapWayland;
class SurfacePixmapX11;
class WindowItem;
class WindowPixmap;
// The base class for compositing backends.
class KWIN_EXPORT Scene : public QObject
@ -203,6 +206,10 @@ public:
return {};
}
virtual PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap);
virtual PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap);
virtual PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap);
Q_SIGNALS:
void frameRendered();
void resetCompositing();
@ -373,14 +380,6 @@ public:
return {};
}
/**
* @brief Factory method to create a WindowPixmap.
*
* The inheriting classes need to implement this method to create a new instance of their WindowPixmap subclass.
* @note Do not use WindowPixmap::create on the created instance. The Scene will take care of that.
*/
virtual WindowPixmap *createWindowPixmap() = 0;
protected:
WindowQuadList makeDecorationQuads(const QRect *rects, const QRegion &region) const;
WindowQuadList makeContentsQuads() const;
@ -403,117 +402,6 @@ private:
Q_DISABLE_COPY(Window)
};
/**
* @brief Wrapper for a pixmap of the Scene::Window.
*
* This class encapsulates the functionality to get the pixmap for a window. When initialized the pixmap is not yet
* mapped to the window and isValid will return @c false. The pixmap mapping to the window can be established
* through @ref create. If it succeeds isValid will return @c true, otherwise it will keep in the non valid
* state and it can be tried to create the pixmap mapping again (e.g. in the next frame).
*
* This class is not intended to be updated when the pixmap is no longer valid due to e.g. resizing the window.
* Instead a new instance of this class should be instantiated. The idea behind this is that a valid pixmap does not
* get destroyed, but can continue to be used. To indicate that a newer pixmap should in generally be around, one can
* use markAsDiscarded.
*
* This class is intended to be inherited for the needs of the compositor backends which need further mapping from
* the native pixmap to the respective rendering format.
*/
class KWIN_EXPORT WindowPixmap : public QObject
{
Q_OBJECT
public:
virtual ~WindowPixmap();
/**
* @brief Tries to create the mapping between the Window and the pixmap.
*
* In case this method succeeds in creating the pixmap for the window, isValid will return @c true otherwise
* @c false.
*
* Inheriting classes should re-implement this method in case they need to add further functionality for mapping the
* native pixmap to the rendering format.
*/
virtual void create();
/**
* @brief Recursively updates the mapping between the WindowPixmap and the buffer.
*/
virtual void update();
/**
* @return @c true if the pixmap has been created and is valid, @c false otherwise
*/
virtual bool isValid() const;
/**
* @return The native X11 pixmap handle
*/
xcb_pixmap_t pixmap() const;
/**
* @return The Wayland BufferInterface for this WindowPixmap.
*/
KWaylandServer::BufferInterface *buffer() const;
const QSharedPointer<QOpenGLFramebufferObject> &fbo() const;
QImage internalImage() 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.
*
* @return @c true if this WindowPixmap is considered as discarded, @c false otherwise.
* @see markAsDiscarded
*/
bool isDiscarded() const;
/**
* @brief Marks this WindowPixmap as discarded. From now on isDiscarded will return @c true. This method should
* only be used by the Window when it changes in a way that a new pixmap is required.
*
* @see isDiscarded
*/
void markAsDiscarded();
/**
* The size of the pixmap.
*/
const QSize &size() const;
/**
* The geometry of the Client's content inside the pixmap. In case of a decorated Client the
* pixmap also contains the decoration which is not rendered into this pixmap, though. This
* contentsRect tells where inside the complete pixmap the real content is.
*/
const QRect &contentsRect() const;
/**
* @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() const;
/**
* Returns @c true if the attached buffer has an alpha channel; otherwise returns @c false.
*/
bool hasAlphaChannel() const;
/**
* @returns the surface this WindowPixmap references, might be @c null.
*/
KWaylandServer::SurfaceInterface *surface() const;
void setSurface(KWaylandServer::SurfaceInterface *surface);
protected:
explicit WindowPixmap(Scene::Window *window);
/**
* @return The Window this WindowPixmap belongs to
*/
Scene::Window *window();
private:
void setBuffer(KWaylandServer::BufferInterface *buffer);
void clear();
Scene::Window *m_window;
xcb_pixmap_t m_pixmap;
QSize m_pixmapSize;
bool m_discarded;
QRect m_contentsRect;
KWaylandServer::BufferInterface *m_buffer = nullptr;
QSharedPointer<QOpenGLFramebufferObject> m_fbo;
QImage m_internalImage;
QPointer<KWaylandServer::SurfaceInterface> m_surface;
};
class Scene::EffectFrame
{
public:
@ -585,61 +473,6 @@ Toplevel* Scene::Window::window() const
return toplevel;
}
inline
KWaylandServer::BufferInterface *WindowPixmap::buffer() const
{
return m_buffer;
}
inline
const QSharedPointer<QOpenGLFramebufferObject> &WindowPixmap::fbo() const
{
return m_fbo;
}
inline
QImage WindowPixmap::internalImage() const
{
return m_internalImage;
}
inline
Toplevel* WindowPixmap::toplevel() const
{
return m_window->window();
}
inline
xcb_pixmap_t WindowPixmap::pixmap() const
{
return m_pixmap;
}
inline
bool WindowPixmap::isDiscarded() const
{
return m_discarded;
}
inline
void WindowPixmap::markAsDiscarded()
{
m_discarded = true;
m_window->referencePreviousPixmap();
}
inline
const QRect &WindowPixmap::contentsRect() const
{
return m_contentsRect;
}
inline
const QSize &WindowPixmap::size() const
{
return m_pixmapSize;
}
} // namespace
Q_DECLARE_INTERFACE(KWin::SceneFactory, "org.kde.kwin.Scene")

View file

@ -48,51 +48,51 @@ QRegion SurfaceItem::damage() const
return m_damage;
}
WindowPixmap *SurfaceItem::windowPixmap() const
SurfacePixmap *SurfaceItem::pixmap() const
{
if (m_windowPixmap && m_windowPixmap->isValid()) {
return m_windowPixmap.data();
if (m_pixmap && m_pixmap->isValid()) {
return m_pixmap.data();
}
if (m_previousWindowPixmap && m_previousWindowPixmap->isValid()) {
return m_previousWindowPixmap.data();
if (m_previousPixmap && m_previousPixmap->isValid()) {
return m_previousPixmap.data();
}
return nullptr;
}
WindowPixmap *SurfaceItem::previousWindowPixmap() const
SurfacePixmap *SurfaceItem::previousPixmap() const
{
return m_previousWindowPixmap.data();
return m_previousPixmap.data();
}
void SurfaceItem::referencePreviousPixmap()
{
if (m_previousWindowPixmap && m_previousWindowPixmap->isDiscarded()) {
if (m_previousPixmap && m_previousPixmap->isDiscarded()) {
m_referencePixmapCounter++;
}
}
void SurfaceItem::unreferencePreviousPixmap()
{
if (!m_previousWindowPixmap || !m_previousWindowPixmap->isDiscarded()) {
if (!m_previousPixmap || !m_previousPixmap->isDiscarded()) {
return;
}
m_referencePixmapCounter--;
if (m_referencePixmapCounter == 0) {
m_previousWindowPixmap.reset();
m_previousPixmap.reset();
}
}
void SurfaceItem::updatePixmap()
{
if (m_windowPixmap.isNull()) {
m_windowPixmap.reset(createPixmap());
if (m_pixmap.isNull()) {
m_pixmap.reset(createPixmap());
}
if (m_windowPixmap->isValid()) {
m_windowPixmap->update();
if (m_pixmap->isValid()) {
m_pixmap->update();
} else {
m_windowPixmap->create();
if (m_windowPixmap->isValid()) {
m_previousWindowPixmap.reset();
m_pixmap->create();
if (m_pixmap->isValid()) {
m_previousPixmap.reset();
discardQuads();
}
}
@ -100,12 +100,13 @@ void SurfaceItem::updatePixmap()
void SurfaceItem::discardPixmap()
{
if (!m_windowPixmap.isNull()) {
if (m_windowPixmap->isValid()) {
m_previousWindowPixmap.reset(m_windowPixmap.take());
m_previousWindowPixmap->markAsDiscarded();
if (!m_pixmap.isNull()) {
if (m_pixmap->isValid()) {
m_previousPixmap.reset(m_pixmap.take());
m_previousPixmap->markAsDiscarded();
m_referencePixmapCounter++;
} else {
m_windowPixmap.reset();
m_pixmap.reset();
}
}
addDamage(rect());
@ -116,4 +117,48 @@ void SurfaceItem::preprocess()
updatePixmap();
}
PlatformSurfaceTexture::~PlatformSurfaceTexture()
{
}
SurfacePixmap::SurfacePixmap(PlatformSurfaceTexture *platformTexture, QObject *parent)
: QObject(parent)
, m_platformTexture(platformTexture)
{
}
void SurfacePixmap::update()
{
}
PlatformSurfaceTexture *SurfacePixmap::platformTexture() const
{
return m_platformTexture.data();
}
bool SurfacePixmap::hasAlphaChannel() const
{
return m_hasAlphaChannel;
}
QSize SurfacePixmap::size() const
{
return m_size;
}
QRect SurfacePixmap::contentsRect() const
{
return m_contentsRect;
}
bool SurfacePixmap::isDiscarded() const
{
return m_isDiscarded;
}
void SurfacePixmap::markAsDiscarded()
{
m_isDiscarded = true;
}
} // namespace KWin

View file

@ -11,6 +11,8 @@
namespace KWin
{
class SurfacePixmap;
/**
* The SurfaceItem class represents a surface with some contents.
*/
@ -29,8 +31,8 @@ public:
void resetDamage();
QRegion damage() const;
WindowPixmap *windowPixmap() const;
WindowPixmap *previousWindowPixmap() const;
SurfacePixmap *pixmap() const;
SurfacePixmap *previousPixmap() const;
void referencePreviousPixmap();
void unreferencePreviousPixmap();
@ -38,18 +40,57 @@ public:
protected:
explicit SurfaceItem(Scene::Window *window, Item *parent = nullptr);
virtual WindowPixmap *createPixmap() = 0;
virtual SurfacePixmap *createPixmap() = 0;
void preprocess() override;
void discardPixmap();
void updatePixmap();
QRegion m_damage;
QScopedPointer<WindowPixmap> m_windowPixmap;
QScopedPointer<WindowPixmap> m_previousWindowPixmap;
QScopedPointer<SurfacePixmap> m_pixmap;
QScopedPointer<SurfacePixmap> m_previousPixmap;
int m_referencePixmapCounter = 0;
friend class Scene::Window;
};
class KWIN_EXPORT PlatformSurfaceTexture
{
public:
virtual ~PlatformSurfaceTexture();
virtual bool isValid() const = 0;
};
class KWIN_EXPORT SurfacePixmap : public QObject
{
Q_OBJECT
public:
explicit SurfacePixmap(PlatformSurfaceTexture *platformTexture, QObject *parent = nullptr);
PlatformSurfaceTexture *platformTexture() const;
bool hasAlphaChannel() const;
QSize size() const;
QRect contentsRect() const;
bool isDiscarded() const;
void markAsDiscarded();
virtual void create() = 0;
virtual void update();
virtual bool isValid() const = 0;
protected:
QSize m_size;
QRect m_contentsRect;
bool m_hasAlphaChannel = false;
private:
QScopedPointer<PlatformSurfaceTexture> m_platformTexture;
bool m_isDiscarded = false;
};
} // namespace KWin

View file

@ -5,6 +5,8 @@
*/
#include "surfaceitem_internal.h"
#include "composite.h"
#include "scene.h"
namespace KWin
{
@ -30,9 +32,9 @@ QRegion SurfaceItemInternal::shape() const
return QRegion(0, 0, width(), height());
}
WindowPixmap *SurfaceItemInternal::createPixmap()
SurfacePixmap *SurfaceItemInternal::createPixmap()
{
return window()->createWindowPixmap();
return new SurfacePixmapInternal(this);
}
void SurfaceItemInternal::handleBufferGeometryChanged(Toplevel *toplevel, const QRect &old)
@ -43,4 +45,43 @@ void SurfaceItemInternal::handleBufferGeometryChanged(Toplevel *toplevel, const
setSize(toplevel->bufferGeometry().size());
}
SurfacePixmapInternal::SurfacePixmapInternal(SurfaceItemInternal *item, QObject *parent)
: SurfacePixmap(Compositor::self()->scene()->createPlatformSurfaceTextureInternal(this), parent)
, m_item(item)
{
}
QOpenGLFramebufferObject *SurfacePixmapInternal::fbo() const
{
return m_fbo.data();
}
QImage SurfacePixmapInternal::image() const
{
return m_rasterBuffer;
}
void SurfacePixmapInternal::create()
{
update();
}
void SurfacePixmapInternal::update()
{
const Toplevel *toplevel = m_item->window()->window();
if (toplevel->internalFramebufferObject()) {
m_fbo = toplevel->internalFramebufferObject();
m_hasAlphaChannel = true;
} else if (!toplevel->internalImageObject().isNull()) {
m_rasterBuffer = toplevel->internalImageObject();
m_hasAlphaChannel = m_rasterBuffer.hasAlphaChannel();
}
}
bool SurfacePixmapInternal::isValid() const
{
return !m_fbo.isNull() || !m_rasterBuffer.isNull();
}
} // namespace KWin

View file

@ -28,7 +28,27 @@ private Q_SLOTS:
void handleBufferGeometryChanged(Toplevel *toplevel, const QRect &old);
protected:
WindowPixmap *createPixmap() override;
SurfacePixmap *createPixmap() override;
};
class KWIN_EXPORT SurfacePixmapInternal final : public SurfacePixmap
{
Q_OBJECT
public:
explicit SurfacePixmapInternal(SurfaceItemInternal *item, QObject *parent = nullptr);
QOpenGLFramebufferObject *fbo() const;
QImage image() const;
void create() override;
void update() override;
bool isValid() const override;
private:
SurfaceItemInternal *m_item;
QSharedPointer<QOpenGLFramebufferObject> m_fbo;
QImage m_rasterBuffer;
};
} // namespace KWin

View file

@ -5,7 +5,10 @@
*/
#include "surfaceitem_wayland.h"
#include "composite.h"
#include "scene.h"
#include <KWaylandServer/buffer_interface.h>
#include <KWaylandServer/subcompositor_interface.h>
#include <KWaylandServer/surface_interface.h>
@ -123,11 +126,74 @@ void SurfaceItemWayland::handleSubSurfacePositionChanged()
setPosition(m_surface->subSurface()->position());
}
WindowPixmap *SurfaceItemWayland::createPixmap()
SurfacePixmap *SurfaceItemWayland::createPixmap()
{
WindowPixmap *pixmap = window()->createWindowPixmap();
pixmap->setSurface(m_surface);
return pixmap;
return new SurfacePixmapWayland(this);
}
SurfacePixmapWayland::SurfacePixmapWayland(SurfaceItemWayland *item, QObject *parent)
: SurfacePixmap(Compositor::self()->scene()->createPlatformSurfaceTextureWayland(this), parent)
, m_item(item)
{
}
SurfacePixmapWayland::~SurfacePixmapWayland()
{
setBuffer(nullptr);
}
KWaylandServer::SurfaceInterface *SurfacePixmapWayland::surface() const
{
return m_item->surface();
}
KWaylandServer::BufferInterface *SurfacePixmapWayland::buffer() const
{
return m_buffer;
}
void SurfacePixmapWayland::create()
{
update();
}
void SurfacePixmapWayland::update()
{
KWaylandServer::SurfaceInterface *surface = m_item->surface();
if (surface) {
setBuffer(surface->buffer());
}
}
bool SurfacePixmapWayland::isValid() const
{
// Referenced buffers get destroyed under our nose, check also the platform texture
// to work around BufferInterface's weird api.
return m_buffer || platformTexture()->isValid();
}
void SurfacePixmapWayland::clearBuffer()
{
setBuffer(nullptr);
}
void SurfacePixmapWayland::setBuffer(KWaylandServer::BufferInterface *buffer)
{
if (m_buffer == buffer) {
return;
}
if (m_buffer) {
disconnect(m_buffer, &KWaylandServer::BufferInterface::aboutToBeDestroyed,
this, &SurfacePixmapWayland::clearBuffer);
m_buffer->unref();
}
m_buffer = buffer;
if (m_buffer) {
m_buffer->ref();
connect(m_buffer, &KWaylandServer::BufferInterface::aboutToBeDestroyed,
this, &SurfacePixmapWayland::clearBuffer);
m_hasAlphaChannel = m_buffer->hasAlphaChannel();
}
}
SurfaceItemXwayland::SurfaceItemXwayland(Scene::Window *window, Item *parent)

View file

@ -38,13 +38,36 @@ private Q_SLOTS:
void handleSubSurfacePositionChanged();
protected:
WindowPixmap *createPixmap() override;
SurfacePixmap *createPixmap() override;
private:
QPointer<KWaylandServer::SurfaceInterface> m_surface;
QHash<KWaylandServer::SubSurfaceInterface *, SurfaceItemWayland *> m_subsurfaces;
};
class KWIN_EXPORT SurfacePixmapWayland final : public SurfacePixmap
{
Q_OBJECT
public:
explicit SurfacePixmapWayland(SurfaceItemWayland *item, QObject *parent = nullptr);
~SurfacePixmapWayland() override;
KWaylandServer::SurfaceInterface *surface() const;
KWaylandServer::BufferInterface *buffer() const;
void create() override;
void update() override;
bool isValid() const override;
private:
void clearBuffer();
void setBuffer(KWaylandServer::BufferInterface *buffer);
SurfaceItemWayland *m_item;
KWaylandServer::BufferInterface *m_buffer = nullptr;
};
/**
* The SurfaceItemXwayland class represents an Xwayland surface in the scene.
*/

View file

@ -5,6 +5,8 @@
*/
#include "surfaceitem_x11.h"
#include "composite.h"
#include "scene.h"
namespace KWin
{
@ -135,9 +137,81 @@ QRegion SurfaceItemX11::opaque() const
return window()->window()->opaqueRegion();
}
WindowPixmap *SurfaceItemX11::createPixmap()
SurfacePixmap *SurfaceItemX11::createPixmap()
{
return window()->createWindowPixmap();
return new SurfacePixmapX11(this);
}
SurfacePixmapX11::SurfacePixmapX11(SurfaceItemX11 *item, QObject *parent)
: SurfacePixmap(Compositor::self()->scene()->createPlatformSurfaceTextureX11(this), parent)
, m_item(item)
{
}
SurfacePixmapX11::~SurfacePixmapX11()
{
if (m_pixmap != XCB_PIXMAP_NONE) {
xcb_free_pixmap(kwinApp()->x11Connection(), m_pixmap);
}
}
bool SurfacePixmapX11::isValid() const
{
return m_pixmap != XCB_PIXMAP_NONE;
}
xcb_pixmap_t SurfacePixmapX11::pixmap() const
{
return m_pixmap;
}
xcb_visualid_t SurfacePixmapX11::visual() const
{
return m_item->window()->window()->visual();
}
void SurfacePixmapX11::create()
{
const Toplevel *toplevel = m_item->window()->window();
if (toplevel->isDeleted()) {
return;
}
XServerGrabber grabber;
xcb_connection_t *connection = kwinApp()->x11Connection();
xcb_window_t frame = toplevel->frameId();
xcb_pixmap_t pixmap = xcb_generate_id(connection);
xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection,
frame,
pixmap);
Xcb::WindowAttributes windowAttributes(frame);
Xcb::WindowGeometry windowGeometry(frame);
if (xcb_generic_error_t *error = xcb_request_check(connection, namePixmapCookie)) {
qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x (error code %d)",
toplevel->window(), error->error_code);
free(error);
return;
}
// check that the received pixmap is valid and actually matches what we
// know about the window (i.e. size)
if (!windowAttributes || windowAttributes->map_state != XCB_MAP_STATE_VIEWABLE) {
qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x (not viewable)",
toplevel->window());
xcb_free_pixmap(connection, pixmap);
return;
}
const QRect bufferGeometry = toplevel->bufferGeometry();
if (windowGeometry.size() != bufferGeometry.size()) {
qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x (mismatched geometry)",
toplevel->window());
xcb_free_pixmap(connection, pixmap);
return;
}
m_pixmap = pixmap;
m_hasAlphaChannel = toplevel->hasAlpha();
m_size = bufferGeometry.size();
m_contentsRect = QRect(toplevel->clientPos(), toplevel->clientSize());
}
} // namespace KWin

View file

@ -35,7 +35,7 @@ private Q_SLOTS:
void handleBufferGeometryChanged(Toplevel *toplevel, const QRect &old);
protected:
WindowPixmap *createPixmap() override;
SurfacePixmap *createPixmap() override;
private:
xcb_damage_damage_t m_damageHandle = XCB_NONE;
@ -44,4 +44,23 @@ private:
bool m_havePendingDamageRegion = false;
};
class KWIN_EXPORT SurfacePixmapX11 final : public SurfacePixmap
{
Q_OBJECT
public:
explicit SurfacePixmapX11(SurfaceItemX11 *item, QObject *parent = nullptr);
~SurfacePixmapX11() override;
xcb_pixmap_t pixmap() const;
xcb_visualid_t visual() const;
void create() override;
bool isValid() const override;
private:
SurfaceItemX11 *m_item;
xcb_pixmap_t m_pixmap = XCB_PIXMAP_NONE;
};
} // namespace KWaylandServer