diff --git a/src/platformsupport/scenes/opengl/CMakeLists.txt b/src/platformsupport/scenes/opengl/CMakeLists.txt index 7fcce9f511..e677113cbb 100644 --- a/src/platformsupport/scenes/opengl/CMakeLists.txt +++ b/src/platformsupport/scenes/opengl/CMakeLists.txt @@ -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) diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp index afd8a3a7c3..99cea0c56e 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -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 #include -#include // kwin libs #include #include #include // Qt #include -#include #include 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 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 ®ion) -{ - // 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(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(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 &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 ®ion, 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 ®ion) -{ - 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; -} - } diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.h b/src/platformsupport/scenes/opengl/abstract_egl_backend.h index b47d02fbd4..169774c266 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.h +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -9,21 +9,27 @@ #ifndef KWIN_ABSTRACT_EGL_BACKEND_H #define KWIN_ABSTRACT_EGL_BACKEND_H #include "openglbackend.h" -#include "texture.h" #include #include -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 ®ion) 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 &buffer); - bool loadEglTexture(const QPointer &buffer); - bool loadDmabufTexture(const QPointer< KWaylandServer::BufferInterface > &buffer); - bool loadInternalImageObject(WindowPixmap *pixmap); - EGLImageKHR attach(const QPointer &buffer); - bool updateFromFBO(const QSharedPointer &fbo); - bool updateFromInternalImageObject(WindowPixmap *pixmap, const QRegion ®ion); - SceneOpenGLTexture *q; - AbstractEglBackend *m_backend; - EGLImageKHR m_image; -}; - } #endif diff --git a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_internal.cpp b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_internal.cpp new file mode 100644 index 0000000000..0de7325f65 --- /dev/null +++ b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_internal.cpp @@ -0,0 +1,91 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "basiceglsurfacetexture_internal.h" +#include "kwingltexture.h" +#include "logging.h" +#include "surfaceitem_internal.h" + +#include + +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 ®ion) +{ + 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 ®ion, 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 ®ion) +{ + 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 diff --git a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_internal.h b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_internal.h new file mode 100644 index 0000000000..8605385d17 --- /dev/null +++ b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_internal.h @@ -0,0 +1,27 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 ®ion) override; + +private: + bool updateFromFramebuffer(); + bool updateFromImage(const QRegion ®ion); +}; + +} // namespace KWin diff --git a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp new file mode 100644 index 0000000000..c4beccee40 --- /dev/null +++ b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp @@ -0,0 +1,244 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 + +#include +#include +#include + +namespace KWin +{ + +BasicEGLSurfaceTextureWayland::BasicEGLSurfaceTextureWayland(OpenGLBackend *backend, + SurfacePixmapWayland *pixmap) + : PlatformOpenGLSurfaceTextureWayland(backend, pixmap) +{ +} + +BasicEGLSurfaceTextureWayland::~BasicEGLSurfaceTextureWayland() +{ + destroy(); +} + +AbstractEglBackend *BasicEGLSurfaceTextureWayland::backend() const +{ + return static_cast(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 ®ion) +{ + 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 ®ion) +{ + 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(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(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(buffer->linuxDmabufBuffer()); + m_texture->bind(); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast(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(buffer->resource()), attribs); + if (image != EGL_NO_IMAGE_KHR) { + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast(image)); + m_texture->setYInverted(yInverted); + } + return image; +} + +} // namespace KWin diff --git a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h new file mode 100644 index 0000000000..373e8b48f1 --- /dev/null +++ b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h @@ -0,0 +1,51 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include "platformopenglsurfacetexture_wayland.h" + +#include + +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 ®ion) override; + +private: + bool loadShmTexture(KWaylandServer::BufferInterface *buffer); + void updateShmTexture(KWaylandServer::BufferInterface *buffer, const QRegion ®ion); + 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 diff --git a/src/platformsupport/scenes/opengl/openglbackend.cpp b/src/platformsupport/scenes/opengl/openglbackend.cpp index a4ba52ff82..3cab144d62 100644 --- a/src/platformsupport/scenes/opengl/openglbackend.cpp +++ b/src/platformsupport/scenes/opengl/openglbackend.cpp @@ -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; +} + } diff --git a/src/platformsupport/scenes/opengl/openglbackend.h b/src/platformsupport/scenes/opengl/openglbackend.h index 6cabb81a32..35a3804de0 100644 --- a/src/platformsupport/scenes/opengl/openglbackend.h +++ b/src/platformsupport/scenes/opengl/openglbackend.h @@ -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. diff --git a/src/platformsupport/scenes/opengl/platformopenglsurfacetexture.cpp b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture.cpp new file mode 100644 index 0000000000..febcab8589 --- /dev/null +++ b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture.cpp @@ -0,0 +1,37 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 diff --git a/src/platformsupport/scenes/opengl/platformopenglsurfacetexture.h b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture.h new file mode 100644 index 0000000000..8cf9021946 --- /dev/null +++ b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture.h @@ -0,0 +1,36 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 ®ion) = 0; + +protected: + OpenGLBackend *m_backend; + QScopedPointer m_texture; +}; + +} // namespace KWin diff --git a/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_internal.cpp b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_internal.cpp new file mode 100644 index 0000000000..93e7169a20 --- /dev/null +++ b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_internal.cpp @@ -0,0 +1,19 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 diff --git a/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_internal.h b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_internal.h new file mode 100644 index 0000000000..24d6e272cf --- /dev/null +++ b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_internal.h @@ -0,0 +1,23 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 diff --git a/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_wayland.cpp b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_wayland.cpp new file mode 100644 index 0000000000..d6a5d394a0 --- /dev/null +++ b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_wayland.cpp @@ -0,0 +1,19 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 diff --git a/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_wayland.h b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_wayland.h new file mode 100644 index 0000000000..4c244fce7c --- /dev/null +++ b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_wayland.h @@ -0,0 +1,23 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 diff --git a/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_x11.cpp b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_x11.cpp new file mode 100644 index 0000000000..202e01d04a --- /dev/null +++ b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_x11.cpp @@ -0,0 +1,19 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 diff --git a/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_x11.h b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_x11.h new file mode 100644 index 0000000000..e46325932b --- /dev/null +++ b/src/platformsupport/scenes/opengl/platformopenglsurfacetexture_x11.h @@ -0,0 +1,23 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 diff --git a/src/platformsupport/scenes/opengl/texture.cpp b/src/platformsupport/scenes/opengl/texture.cpp deleted file mode 100644 index b52a928ca6..0000000000 --- a/src/platformsupport/scenes/opengl/texture.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2006 Lubos Lunak - SPDX-FileCopyrightText: 2009, 2010, 2011 Martin Gräßlin - - 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 ®ion) -{ - Q_D(SceneOpenGLTexture); - d->updateTexture(pixmap, region); -} - -SceneOpenGLTexturePrivate::SceneOpenGLTexturePrivate() -{ -} - -SceneOpenGLTexturePrivate::~SceneOpenGLTexturePrivate() -{ -} - -void SceneOpenGLTexturePrivate::updateTexture(WindowPixmap *pixmap, const QRegion ®ion) -{ - Q_UNUSED(pixmap) - Q_UNUSED(region) -} - -} diff --git a/src/platformsupport/scenes/opengl/texture.h b/src/platformsupport/scenes/opengl/texture.h deleted file mode 100644 index 68ab0ee892..0000000000 --- a/src/platformsupport/scenes/opengl/texture.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2006 Lubos Lunak - SPDX-FileCopyrightText: 2009, 2010, 2011 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#pragma once - -#include -#include - -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 ®ion); - - 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 ®ion); - virtual OpenGLBackend *backend() = 0; - -protected: - SceneOpenGLTexturePrivate(); - -private: - Q_DISABLE_COPY(SceneOpenGLTexturePrivate) -}; - -} diff --git a/src/platformsupport/scenes/qpainter/CMakeLists.txt b/src/platformsupport/scenes/qpainter/CMakeLists.txt index 01f3eb03e2..bcdbd058c2 100644 --- a/src/platformsupport/scenes/qpainter/CMakeLists.txt +++ b/src/platformsupport/scenes/qpainter/CMakeLists.txt @@ -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) diff --git a/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture.cpp b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture.cpp new file mode 100644 index 0000000000..b2fbe39add --- /dev/null +++ b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture.cpp @@ -0,0 +1,32 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 diff --git a/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture.h b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture.h new file mode 100644 index 0000000000..9709c9f947 --- /dev/null +++ b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture.h @@ -0,0 +1,36 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include "surfaceitem.h" + +#include + +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 ®ion) = 0; + +protected: + QPainterBackend *m_backend; + QImage m_image; +}; + +} // namespace KWin diff --git a/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_internal.cpp b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_internal.cpp new file mode 100644 index 0000000000..acbb805bcf --- /dev/null +++ b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_internal.cpp @@ -0,0 +1,32 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 ®ion) +{ + Q_UNUSED(region) + m_image = m_pixmap->image(); +} + +} // namespace KWin diff --git a/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_internal.h b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_internal.h new file mode 100644 index 0000000000..544ee98e52 --- /dev/null +++ b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_internal.h @@ -0,0 +1,26 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 ®ion) override; + +private: + SurfacePixmapInternal *m_pixmap; +}; + +} // namespace KWin diff --git a/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_wayland.cpp b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_wayland.cpp new file mode 100644 index 0000000000..e3dbc374f8 --- /dev/null +++ b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_wayland.cpp @@ -0,0 +1,55 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "platformqpaintersurfacetexture_wayland.h" +#include "surfaceitem_wayland.h" + +#include +#include + +#include + +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 ®ion) +{ + 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 diff --git a/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_wayland.h b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_wayland.h new file mode 100644 index 0000000000..a375ebe545 --- /dev/null +++ b/src/platformsupport/scenes/qpainter/platformqpaintersurfacetexture_wayland.h @@ -0,0 +1,26 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + 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 ®ion) override; + +private: + SurfacePixmapWayland *m_pixmap; +}; + +} // namespace KWin diff --git a/src/platformsupport/scenes/qpainter/qpainterbackend.cpp b/src/platformsupport/scenes/qpainter/qpainterbackend.cpp index a8bcff4d80..f6cb7e15f1 100644 --- a/src/platformsupport/scenes/qpainter/qpainterbackend.cpp +++ b/src/platformsupport/scenes/qpainter/qpainterbackend.cpp @@ -7,6 +7,8 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #include "qpainterbackend.h" +#include "platformqpaintersurfacetexture_internal.h" +#include "platformqpaintersurfacetexture_wayland.h" #include #include @@ -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) diff --git a/src/platformsupport/scenes/qpainter/qpainterbackend.h b/src/platformsupport/scenes/qpainter/qpainterbackend.h index 5cc551d156..76c42230d7 100644 --- a/src/platformsupport/scenes/qpainter/qpainterbackend.h +++ b/src/platformsupport/scenes/qpainter/qpainterbackend.h @@ -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; /** diff --git a/src/platformsupport/scenes/xrender/CMakeLists.txt b/src/platformsupport/scenes/xrender/CMakeLists.txt index 0bcf5816bf..41f737bd5c 100644 --- a/src/platformsupport/scenes/xrender/CMakeLists.txt +++ b/src/platformsupport/scenes/xrender/CMakeLists.txt @@ -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 diff --git a/src/platformsupport/scenes/xrender/platformxrendersurfacetexture_x11.cpp b/src/platformsupport/scenes/xrender/platformxrendersurfacetexture_x11.cpp new file mode 100644 index 0000000000..85496c0d4d --- /dev/null +++ b/src/platformsupport/scenes/xrender/platformxrendersurfacetexture_x11.cpp @@ -0,0 +1,59 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "platformxrendersurfacetexture_x11.h" +#include "main.h" +#include "surfaceitem_x11.h" + +#include + +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 diff --git a/src/platformsupport/scenes/xrender/platformxrendersurfacetexture_x11.h b/src/platformsupport/scenes/xrender/platformxrendersurfacetexture_x11.h new file mode 100644 index 0000000000..ced97a4d01 --- /dev/null +++ b/src/platformsupport/scenes/xrender/platformxrendersurfacetexture_x11.h @@ -0,0 +1,32 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include "surfaceitem_x11.h" + +#include + +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 diff --git a/src/plugins/platforms/drm/egl_gbm_backend.cpp b/src/plugins/platforms/drm/egl_gbm_backend.cpp index 9079cae17f..81734d01eb 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/src/plugins/platforms/drm/egl_gbm_backend.cpp @@ -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; - } diff --git a/src/plugins/platforms/drm/egl_gbm_backend.h b/src/plugins/platforms/drm/egl_gbm_backend.h index 0b815f8683..c853005199 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.h +++ b/src/plugins/platforms/drm/egl_gbm_backend.h @@ -10,6 +10,8 @@ #define KWIN_EGL_GBM_BACKEND_H #include "abstract_egl_drm_backend.h" +#include + #include 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 diff --git a/src/plugins/platforms/drm/egl_multi_backend.cpp b/src/plugins/platforms/drm/egl_multi_backend.cpp index 52707d6d79..705dd26f9d 100644 --- a/src/plugins/platforms/drm/egl_multi_backend.cpp +++ b/src/plugins/platforms/drm/egl_multi_backend.cpp @@ -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 EglMultiBackend::textureForOutput(AbstractOutput *requestedOutput) const diff --git a/src/plugins/platforms/drm/egl_multi_backend.h b/src/plugins/platforms/drm/egl_multi_backend.h index 93e9c0fa83..574e625f67 100644 --- a/src/plugins/platforms/drm/egl_multi_backend.h +++ b/src/plugins/platforms/drm/egl_multi_backend.h @@ -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 textureForOutput(AbstractOutput *requestedOutput) const override; void screenGeometryChanged(const QSize &size) override; @@ -49,7 +50,6 @@ private: QVector m_backends; AbstractEglDrmBackend *findBackend(int screenId, int& internalScreenId) const; - }; } diff --git a/src/plugins/platforms/drm/egl_stream_backend.cpp b/src/plugins/platforms/drm/egl_stream_backend.cpp index bca18e53eb..80a9e52b8f 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.cpp +++ b/src/plugins/platforms/drm/egl_stream_backend.cpp @@ -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 +#include #include #include #include @@ -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 ®ion) +void EglStreamSurfaceTextureWayland::update(const QRegion ®ion) { 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 ®ion } } else { // Not an EGLStream surface - AbstractEglTexture::updateTexture(pixmap, region); + BasicEGLSurfaceTextureWayland::update(region); } } diff --git a/src/plugins/platforms/drm/egl_stream_backend.h b/src/plugins/platforms/drm/egl_stream_backend.h index 714b1239ab..73cadf2913 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.h +++ b/src/plugins/platforms/drm/egl_stream_backend.h @@ -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 #include #include @@ -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 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 ®ion) override; + EglStreamSurfaceTextureWayland(EglStreamBackend *backend, SurfacePixmapWayland *pixmap); + ~EglStreamSurfaceTextureWayland() override; + + bool create() override; + void update(const QRegion ®ion) 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 diff --git a/src/plugins/platforms/virtual/egl_gbm_backend.cpp b/src/plugins/platforms/virtual/egl_gbm_backend.cpp index 704922bfe7..956760748f 100644 --- a/src/plugins/platforms/virtual/egl_gbm_backend.cpp +++ b/src/plugins/platforms/virtual/egl_gbm_backend.cpp @@ -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 diff --git a/src/plugins/platforms/virtual/egl_gbm_backend.h b/src/plugins/platforms/virtual/egl_gbm_backend.h index 4cafb78198..d70a2da35a 100644 --- a/src/plugins/platforms/virtual/egl_gbm_backend.h +++ b/src/plugins/platforms/virtual/egl_gbm_backend.h @@ -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 diff --git a/src/plugins/platforms/wayland/egl_wayland_backend.cpp b/src/plugins/platforms/wayland/egl_wayland_backend.cpp index e5a3fcd84b..4014496d2f 100644 --- a/src/plugins/platforms/wayland/egl_wayland_backend.cpp +++ b/src/plugins/platforms/wayland/egl_wayland_backend.cpp @@ -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; - } } diff --git a/src/plugins/platforms/wayland/egl_wayland_backend.h b/src/plugins/platforms/wayland/egl_wayland_backend.h index 2f8ec227fd..cf6e3f5d32 100644 --- a/src/plugins/platforms/wayland/egl_wayland_backend.h +++ b/src/plugins/platforms/wayland/egl_wayland_backend.h @@ -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); -}; - } } diff --git a/src/plugins/platforms/x11/common/eglonxbackend.cpp b/src/plugins/platforms/x11/common/eglonxbackend.cpp index 533c1095ab..90fc7e432e 100644 --- a/src/plugins/platforms/x11/common/eglonxbackend.cpp +++ b/src/plugins/platforms/x11/common/eglonxbackend.cpp @@ -7,6 +7,8 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #include "eglonxbackend.h" +// kwineffects +#include // kwin #include "main.h" #include "options.h" diff --git a/src/plugins/platforms/x11/standalone/eglbackend.cpp b/src/plugins/platforms/x11/standalone/eglbackend.cpp index 7596bb224d..6a7087b4ed 100644 --- a/src/plugins/platforms/x11/standalone/eglbackend.cpp +++ b/src/plugins/platforms/x11/standalone/eglbackend.cpp @@ -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(m_backend)); + texture->create(m_pixmap); + + m_texture.reset(texture); + return !m_texture->isNull(); +} + +void EglSurfaceTextureX11::update(const QRegion ®ion) +{ + 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(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(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(m_image)); } GLTexturePrivate::onDamage(); } diff --git a/src/plugins/platforms/x11/standalone/eglbackend.h b/src/plugins/platforms/x11/standalone/eglbackend.h index 5d75d16b5b..aefa6448e6 100644 --- a/src/plugins/platforms/x11/standalone/eglbackend.h +++ b/src/plugins/platforms/x11/standalone/eglbackend.h @@ -7,10 +7,15 @@ #pragma once #include "eglonxbackend.h" +#include "platformopenglsurfacetexture_x11.h" + +#include +#include 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 ®ion) override; }; } // namespace KWin diff --git a/src/plugins/platforms/x11/standalone/glxbackend.cpp b/src/plugins/platforms/x11/standalone/glxbackend.cpp index 9ab840eefa..2100dafd05 100644 --- a/src/plugins/platforms/x11/standalone/glxbackend.cpp +++ b/src/plugins/platforms/x11/standalone/glxbackend.cpp @@ -28,6 +28,7 @@ #include "renderloop_p.h" #include "scene.h" #include "screens.h" +#include "surfaceitem_x11.h" #include "xcbutils.h" // kwin libs #include @@ -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(m_backend)); + texture->create(m_pixmap); + + m_texture.reset(texture); + return !m_texture->isNull(); +} + +void GlxSurfaceTextureX11::update(const QRegion ®ion) +{ + 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 diff --git a/src/plugins/platforms/x11/standalone/glxbackend.h b/src/plugins/platforms/x11/standalone/glxbackend.h index 9d487b62ff..cb511ae1eb 100644 --- a/src/plugins/platforms/x11/standalone/glxbackend.h +++ b/src/plugins/platforms/x11/standalone/glxbackend.h @@ -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 #include #include +#include +#include + +#include + +#include + 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 ®ion) override; }; } // namespace diff --git a/src/plugins/platforms/x11/windowed/egl_x11_backend.cpp b/src/plugins/platforms/x11/windowed/egl_x11_backend.cpp index 225004f472..e1d391da12 100644 --- a/src/plugins/platforms/x11/windowed/egl_x11_backend.cpp +++ b/src/plugins/platforms/x11/windowed/egl_x11_backend.cpp @@ -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 diff --git a/src/plugins/platforms/x11/windowed/egl_x11_backend.h b/src/plugins/platforms/x11/windowed/egl_x11_backend.h index fbf866d85f..c6d12d2266 100644 --- a/src/plugins/platforms/x11/windowed/egl_x11_backend.h +++ b/src/plugins/platforms/x11/windowed/egl_x11_backend.h @@ -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 diff --git a/src/plugins/scenes/opengl/scene_opengl.cpp b/src/plugins/scenes/opengl/scene_opengl.cpp index 785f3534c3..f720479c71 100644 --- a/src/plugins/scenes/opengl/scene_opengl.cpp +++ b/src/plugins/scenes/opengl/scene_opengl.cpp @@ -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 QListsurfaceItem()); - auto pixmap = topMost->windowPixmap(); + auto pixmap = topMost->pixmap(); if (!pixmap) { break; } @@ -810,11 +810,6 @@ void SceneOpenGL::extendPaintRegion(QRegion ®ion, 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 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(surfaceItem->windowPixmap()); - if (!pixmap) { + SurfacePixmap *surfacePixmap = surfaceItem->pixmap(); + if (!surfacePixmap) { return false; } - if (pixmap->isDiscarded()) { - return !pixmap->texture()->isNull(); + + auto platformSurfaceTexture = + static_cast(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(item->windowPixmap()); + const SurfacePixmap *surfaceTexture = item->pixmap(); + const PlatformOpenGLSurfaceTexture *platformSurfaceTexture = + static_cast(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(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(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 ®ion, const WindowPai QSharedPointer OpenGLWindow::windowTexture() { - OpenGLWindowPixmap *frame = nullptr; + PlatformOpenGLSurfaceTexture *frame = nullptr; const SurfaceItem *item = surfaceItem(); if (item) { - frame = static_cast(item->windowPixmap()); + frame = static_cast(item->pixmap()->platformTexture()); } if (frame && item->childItems().isEmpty()) { @@ -1606,50 +1633,6 @@ QSharedPointer OpenGLWindow::windowTexture() } } -//**************************************** -// OpenGLWindowPixmap -//**************************************** - -OpenGLWindowPixmap::OpenGLWindowPixmap(Scene::Window *window, SceneOpenGL* scene) - : WindowPixmap(window) - , m_texture(scene->createTexture()) -{ -} - -OpenGLWindowPixmap::~OpenGLWindowPixmap() -{ -} - -bool OpenGLWindowPixmap::bind(const QRegion ®ion) -{ - 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 //**************************************** diff --git a/src/plugins/scenes/opengl/scene_opengl.h b/src/plugins/scenes/opengl/scene_opengl.h index 0d10c0d004..655240a09a 100644 --- a/src/plugins/scenes/opengl/scene_opengl.h +++ b/src/plugins/scenes/opengl/scene_opengl.h @@ -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 ®ion, const WindowPaintData &data) override; QSharedPointer 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 ®ion); - bool isValid() const override; -private: - QScopedPointer m_texture; -}; - class SceneOpenGL::EffectFrame : public Scene::EffectFrame { @@ -304,11 +285,6 @@ private: QScopedPointer m_texture; }; -inline SceneOpenGLTexture* OpenGLWindowPixmap::texture() const -{ - return m_texture.data(); -} - class KWIN_EXPORT OpenGLFactory : public SceneFactory { Q_OBJECT diff --git a/src/plugins/scenes/qpainter/scene_qpainter.cpp b/src/plugins/scenes/qpainter/scene_qpainter.cpp index 3b75f93808..6dd0a43750 100644 --- a/src/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/src/plugins/scenes/qpainter/scene_qpainter.cpp @@ -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(surfaceItem->windowPixmap()); - if (!windowPixmap || !windowPixmap->isValid()) { + const SurfacePixmap *surfaceTexture = surfaceItem->pixmap(); + if (!surfaceTexture || !surfaceTexture->isValid()) { return; } + PlatformQPainterSurfaceTexture *platformSurfaceTexture = + static_cast(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) diff --git a/src/plugins/scenes/qpainter/scene_qpainter.h b/src/plugins/scenes/qpainter/scene_qpainter.h index fdb39f20f7..14aeed0928 100644 --- a/src/plugins/scenes/qpainter/scene_qpainter.h +++ b/src/plugins/scenes/qpainter/scene_qpainter.h @@ -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 ®ion, 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 diff --git a/src/plugins/scenes/xrender/scene_xrender.cpp b/src/plugins/scenes/xrender/scene_xrender.cpp index 1c8cb6db93..e46f30891e 100644 --- a/src/plugins/scenes/xrender/scene_xrender.cpp +++ b/src/plugins/scenes/xrender/scene_xrender.cpp @@ -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(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(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(surfaceItem()->previousWindowPixmap()); - if (previous && previous != pixmap) { + SurfacePixmap *previous = surfaceItem()->previousPixmap(); + if (previous && previous != surfaceTexture) { + auto previousPlatformTexture = + static_cast(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 //**************************************** diff --git a/src/plugins/scenes/xrender/scene_xrender.h b/src/plugins/scenes/xrender/scene_xrender.h index 7d0ec309d7..2135dcf398 100644 --- a/src/plugins/scenes/xrender/scene_xrender.h +++ b/src/plugins/scenes/xrender/scene_xrender.h @@ -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. * diff --git a/src/scene.cpp b/src/scene.cpp index 3d18511834..b9600c730b 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -726,6 +726,24 @@ QVector Scene::openGLPlatformInterfaceExtensions() const return QVector{}; } +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 //**************************************** diff --git a/src/scene.h b/src/scene.h index 0fc689311e..cfd95fa8e8 100644 --- a/src/scene.h +++ b/src/scene.h @@ -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 ®ion) 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 &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 m_fbo; - QImage m_internalImage; - QPointer 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 &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") diff --git a/src/surfaceitem.cpp b/src/surfaceitem.cpp index 154557c89b..b4a5b9ee07 100644 --- a/src/surfaceitem.cpp +++ b/src/surfaceitem.cpp @@ -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 diff --git a/src/surfaceitem.h b/src/surfaceitem.h index 228fbf5d33..adbdc07b4a 100644 --- a/src/surfaceitem.h +++ b/src/surfaceitem.h @@ -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 m_windowPixmap; - QScopedPointer m_previousWindowPixmap; + QScopedPointer m_pixmap; + QScopedPointer 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 m_platformTexture; + bool m_isDiscarded = false; +}; + } // namespace KWin diff --git a/src/surfaceitem_internal.cpp b/src/surfaceitem_internal.cpp index 11cbbc6271..686a105264 100644 --- a/src/surfaceitem_internal.cpp +++ b/src/surfaceitem_internal.cpp @@ -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 diff --git a/src/surfaceitem_internal.h b/src/surfaceitem_internal.h index 5145ff8dc2..65e39ec405 100644 --- a/src/surfaceitem_internal.h +++ b/src/surfaceitem_internal.h @@ -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 m_fbo; + QImage m_rasterBuffer; }; } // namespace KWin diff --git a/src/surfaceitem_wayland.cpp b/src/surfaceitem_wayland.cpp index e2b056228d..bee1ff62ef 100644 --- a/src/surfaceitem_wayland.cpp +++ b/src/surfaceitem_wayland.cpp @@ -5,7 +5,10 @@ */ #include "surfaceitem_wayland.h" +#include "composite.h" +#include "scene.h" +#include #include #include @@ -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) diff --git a/src/surfaceitem_wayland.h b/src/surfaceitem_wayland.h index c44284c253..d6b7e92c1e 100644 --- a/src/surfaceitem_wayland.h +++ b/src/surfaceitem_wayland.h @@ -38,13 +38,36 @@ private Q_SLOTS: void handleSubSurfacePositionChanged(); protected: - WindowPixmap *createPixmap() override; + SurfacePixmap *createPixmap() override; private: QPointer m_surface; QHash 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. */ diff --git a/src/surfaceitem_x11.cpp b/src/surfaceitem_x11.cpp index 04f6f07cb1..aff4196887 100644 --- a/src/surfaceitem_x11.cpp +++ b/src/surfaceitem_x11.cpp @@ -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 diff --git a/src/surfaceitem_x11.h b/src/surfaceitem_x11.h index 6acf5843e3..ad2401dda3 100644 --- a/src/surfaceitem_x11.h +++ b/src/surfaceitem_x11.h @@ -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