diff --git a/src/backends/wayland/wayland_egl_backend.cpp b/src/backends/wayland/wayland_egl_backend.cpp index 5956a5730d..f6b391ed0f 100644 --- a/src/backends/wayland/wayland_egl_backend.cpp +++ b/src/backends/wayland/wayland_egl_backend.cpp @@ -26,6 +26,7 @@ #include // KDE +#include #include // Qt @@ -61,13 +62,13 @@ static QVector regionToRects(const QRegion ®ion, Output *output) return rects; } -WaylandEglOutput::WaylandEglOutput(WaylandOutput *output, WaylandEglBackend *backend) +WaylandEglPrimaryLayer::WaylandEglPrimaryLayer(WaylandOutput *output, WaylandEglBackend *backend) : m_waylandOutput(output) , m_backend(backend) { } -bool WaylandEglOutput::init() +bool WaylandEglPrimaryLayer::init() { auto surface = m_waylandOutput->surface(); const QSize nativeSize = m_waylandOutput->geometry().size() * m_waylandOutput->scale(); @@ -94,35 +95,23 @@ bool WaylandEglOutput::init() return true; } -WaylandEglOutput::~WaylandEglOutput() +WaylandEglPrimaryLayer::~WaylandEglPrimaryLayer() { wl_egl_window_destroy(m_overlay); } -GLFramebuffer *WaylandEglOutput::fbo() const +GLFramebuffer *WaylandEglPrimaryLayer::fbo() const { return m_fbo.get(); } -bool WaylandEglOutput::makeContextCurrent() const +std::optional WaylandEglPrimaryLayer::beginFrame() { - if (m_eglSurface == EGL_NO_SURFACE) { - return false; - } if (eglMakeCurrent(m_backend->eglDisplay(), m_eglSurface, m_eglSurface, m_backend->context()) == EGL_FALSE) { qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed"; - return false; + return std::nullopt; } - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { - qCWarning(KWIN_WAYLAND_BACKEND) << "Error occurred while creating context " << error; - return false; - } - return true; -} -std::optional WaylandEglOutput::beginFrame() -{ const QSize nativeSize = m_waylandOutput->pixelSize(); if (!m_fbo || m_fbo->size() != nativeSize) { m_fbo = std::make_unique(0, nativeSize); @@ -130,9 +119,6 @@ std::optional WaylandEglOutput::beginFrame() wl_egl_window_resize(m_overlay, nativeSize.width(), nativeSize.height(), 0, 0); } - eglWaitNative(EGL_CORE_NATIVE_ENGINE); - makeContextCurrent(); - QRegion repair; if (m_backend->supportsBufferAge()) { repair = m_damageJournal.accumulate(m_bufferAge, infiniteRegion()); @@ -145,14 +131,14 @@ std::optional WaylandEglOutput::beginFrame() }; } -bool WaylandEglOutput::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_damageJournal.add(damagedRegion); GLFramebuffer::popFramebuffer(); return true; } -void WaylandEglOutput::aboutToStartPainting(const QRegion &damage) +void WaylandEglPrimaryLayer::aboutToStartPainting(const QRegion &damage) { if (m_bufferAge > 0 && !damage.isEmpty() && m_backend->supportsPartialUpdate()) { QVector rects = regionToRects(damage, m_waylandOutput); @@ -164,7 +150,7 @@ void WaylandEglOutput::aboutToStartPainting(const QRegion &damage) } } -void WaylandEglOutput::present() +void WaylandEglPrimaryLayer::present() { m_waylandOutput->surface()->setupFrameCallback(); m_waylandOutput->surface()->setScale(std::ceil(m_waylandOutput->scale())); @@ -187,6 +173,81 @@ void WaylandEglOutput::present() } } +WaylandEglCursorLayer::WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend) + : m_output(output) + , m_backend(backend) +{ +} + +WaylandEglCursorLayer::~WaylandEglCursorLayer() +{ + eglMakeCurrent(m_backend->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, m_backend->context()); + m_framebuffer.reset(); + m_texture.reset(); +} + +qreal WaylandEglCursorLayer::scale() const +{ + return m_scale; +} + +void WaylandEglCursorLayer::setScale(qreal scale) +{ + m_scale = scale; +} + +QPoint WaylandEglCursorLayer::hotspot() const +{ + return m_hotspot; +} + +void WaylandEglCursorLayer::setHotspot(const QPoint &hotspot) +{ + m_hotspot = hotspot; +} + +QSize WaylandEglCursorLayer::size() const +{ + return m_size; +} + +void WaylandEglCursorLayer::setSize(const QSize &size) +{ + m_size = size; +} + +std::optional WaylandEglCursorLayer::beginFrame() +{ + if (eglMakeCurrent(m_backend->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, m_backend->context()) == EGL_FALSE) { + qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed"; + return std::nullopt; + } + + const QSize bufferSize = m_size.expandedTo(QSize(64, 64)); + if (!m_texture || m_texture->size() != bufferSize) { + m_texture = std::make_unique(GL_RGBA8, bufferSize); + m_framebuffer = std::make_unique(m_texture.get()); + } + + GLFramebuffer::pushFramebuffer(m_framebuffer.get()); + return OutputLayerBeginFrameInfo{ + .renderTarget = RenderTarget(m_framebuffer.get()), + .repaint = infiniteRegion(), + }; +} + +bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +{ + GLFramebuffer::popFramebuffer(); + + // Technically, we could pass a linux-dmabuf buffer, but host kwin does not support that atm. + const QImage image = m_texture->toImage().mirrored(false, true); + KWayland::Client::Buffer::Ptr buffer = m_output->backend()->display()->shmPool()->createBuffer(image); + m_output->cursor()->update(buffer, m_scale, m_hotspot); + + return true; +} + WaylandEglBackend::WaylandEglBackend(WaylandBackend *b) : AbstractEglBackend() , m_backend(b) @@ -196,13 +257,7 @@ WaylandEglBackend::WaylandEglBackend(WaylandBackend *b) connect(m_backend, &WaylandBackend::outputAdded, this, &WaylandEglBackend::createEglWaylandOutput); connect(m_backend, &WaylandBackend::outputRemoved, this, [this](Output *output) { - auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [output](const auto &o) { - return o->m_waylandOutput == output; - }); - if (it == m_outputs.end()) { - return; - } - m_outputs.erase(it); + m_outputs.erase(output); }); b->setEglBackend(this); @@ -220,11 +275,15 @@ void WaylandEglBackend::cleanupSurfaces() bool WaylandEglBackend::createEglWaylandOutput(Output *waylandOutput) { - const auto output = std::make_shared(static_cast(waylandOutput), this); - if (!output->init()) { + auto cursorLayer = std::make_unique(static_cast(waylandOutput), this); + auto primaryLayer = std::make_unique(static_cast(waylandOutput), this); + if (!primaryLayer->init()) { return false; } - m_outputs.insert(waylandOutput, output); + m_outputs[waylandOutput] = Layers{ + .primaryLayer = std::move(primaryLayer), + .cursorLayer = std::move(cursorLayer), + }; return true; } @@ -293,13 +352,12 @@ bool WaylandEglBackend::initRenderingContext() } } - if (m_outputs.isEmpty()) { + if (m_outputs.empty()) { qCCritical(KWIN_WAYLAND_BACKEND) << "Create Window Surfaces failed"; return false; } - const auto &firstOutput = m_outputs.first(); - return firstOutput->makeContextCurrent(); + return makeCurrent(); } bool WaylandEglBackend::initBufferConfigs() @@ -340,7 +398,7 @@ bool WaylandEglBackend::initBufferConfigs() std::shared_ptr WaylandEglBackend::textureForOutput(KWin::Output *output) const { auto texture = std::make_unique(GL_RGBA8, output->pixelSize()); - GLFramebuffer::pushFramebuffer(m_outputs[output]->fbo()); + GLFramebuffer::pushFramebuffer(m_outputs.at(output).primaryLayer->fbo()); GLFramebuffer renderTarget(texture.get()); renderTarget.blitFromFramebuffer(QRect(0, texture->height(), texture->width(), -texture->height())); GLFramebuffer::popFramebuffer(); @@ -359,12 +417,17 @@ std::unique_ptr WaylandEglBackend::createSurfaceTextureWayland(S void WaylandEglBackend::present(Output *output) { - m_outputs[output]->present(); + m_outputs[output].primaryLayer->present(); } OutputLayer *WaylandEglBackend::primaryLayer(Output *output) { - return m_outputs[output].get(); + return m_outputs[output].primaryLayer.get(); +} + +WaylandEglCursorLayer *WaylandEglBackend::cursorLayer(Output *output) +{ + return m_outputs[output].cursorLayer.get(); } } diff --git a/src/backends/wayland/wayland_egl_backend.h b/src/backends/wayland/wayland_egl_backend.h index 80f33534c0..f8d7fb38c8 100644 --- a/src/backends/wayland/wayland_egl_backend.h +++ b/src/backends/wayland/wayland_egl_backend.h @@ -17,6 +17,8 @@ #include #include +#include + #include class QTemporaryFile; @@ -34,16 +36,15 @@ class WaylandBackend; class WaylandOutput; class WaylandEglBackend; -class WaylandEglOutput : public OutputLayer +class WaylandEglPrimaryLayer : public OutputLayer { public: - WaylandEglOutput(WaylandOutput *output, WaylandEglBackend *backend); - ~WaylandEglOutput() override; + WaylandEglPrimaryLayer(WaylandOutput *output, WaylandEglBackend *backend); + ~WaylandEglPrimaryLayer() override; bool init(); GLFramebuffer *fbo() const; - bool makeContextCurrent() const; void present(); std::optional beginFrame() override; @@ -62,6 +63,36 @@ private: friend class WaylandEglBackend; }; +class WaylandEglCursorLayer : public OutputLayer +{ + Q_OBJECT + +public: + WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend); + ~WaylandEglCursorLayer() override; + + qreal scale() const; + void setScale(qreal scale); + + QPoint hotspot() const; + void setHotspot(const QPoint &hotspot); + + QSize size() const; + void setSize(const QSize &size); + + std::optional beginFrame() override; + bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + +private: + WaylandOutput *m_output; + WaylandEglBackend *m_backend; + std::unique_ptr m_framebuffer; + std::unique_ptr m_texture; + QPoint m_hotspot; + QSize m_size; + qreal m_scale = 1.0; +}; + /** * @brief OpenGL Backend using Egl on a Wayland surface. * @@ -87,6 +118,7 @@ public: void init() override; void present(Output *output) override; OutputLayer *primaryLayer(Output *output) override; + WaylandEglCursorLayer *cursorLayer(Output *output); bool havePlatformBase() const { @@ -105,10 +137,16 @@ private: void cleanupSurfaces() override; - void presentOnSurface(WaylandEglOutput *output, const QRegion &damagedRegion); + void presentOnSurface(WaylandEglPrimaryLayer *output, const QRegion &damagedRegion); + + struct Layers + { + std::unique_ptr primaryLayer; + std::unique_ptr cursorLayer; + }; WaylandBackend *m_backend; - QMap> m_outputs; + std::map m_outputs; bool m_havePlatformBase; friend class EglWaylandTexture; }; diff --git a/src/backends/wayland/wayland_output.cpp b/src/backends/wayland/wayland_output.cpp index 00ba77916f..302dc36315 100644 --- a/src/backends/wayland/wayland_output.cpp +++ b/src/backends/wayland/wayland_output.cpp @@ -8,10 +8,16 @@ */ #include "wayland_output.h" #include "core/renderloop_p.h" +#include "composite.h" #include "wayland_backend.h" #include "wayland_display.h" +#include "wayland_egl_backend.h" +#include "wayland_qpainter_backend.h" #include "wayland_server.h" +#include "kwingltexture.h" +#include "kwinglutils.h" + #include #include #include @@ -21,6 +27,8 @@ #include +#include + #include namespace KWin @@ -73,11 +81,13 @@ void WaylandCursor::disable() void WaylandCursor::update(KWayland::Client::Buffer::Ptr buffer, qreal scale, const QPoint &hotspot) { - m_buffer = buffer; - m_scale = scale; - m_hotspot = hotspot; + if (m_buffer != buffer || m_scale != scale || m_hotspot != hotspot) { + m_buffer = buffer; + m_scale = scale; + m_hotspot = hotspot; - sync(); + sync(); + } } void WaylandCursor::sync() @@ -157,6 +167,11 @@ WaylandCursor *WaylandOutput::cursor() const return m_cursor.get(); } +WaylandBackend *WaylandOutput::backend() const +{ + return m_backend; +} + RenderLoop *WaylandOutput::renderLoop() const { return m_renderLoop.get(); @@ -164,12 +179,17 @@ RenderLoop *WaylandOutput::renderLoop() const bool WaylandOutput::setCursor(const QImage &image, const QPoint &hotspot) { - KWayland::Client::Buffer::Ptr buffer; - if (!image.isNull()) { - buffer = m_backend->display()->shmPool()->createBuffer(image); + if (m_hasPointerLock) { + return false; } - m_cursor->update(buffer, image.devicePixelRatio(), hotspot); - return !m_hasPointerLock; + + if (WaylandEglBackend *backend = qobject_cast(Compositor::self()->backend())) { + renderCursorOpengl(backend, image, hotspot); + } else if (WaylandQPainterBackend *backend = qobject_cast(Compositor::self()->backend())) { + renderCursorQPainter(backend, image, hotspot); + } + + return true; } bool WaylandOutput::moveCursor(const QPoint &position) @@ -178,6 +198,68 @@ bool WaylandOutput::moveCursor(const QPoint &position) return !m_hasPointerLock; } +void WaylandOutput::renderCursorOpengl(WaylandEglBackend *backend, const QImage &image, const QPoint &hotspot) +{ + WaylandEglCursorLayer *cursorLayer = backend->cursorLayer(this); + cursorLayer->setSize(image.size()); + cursorLayer->setScale(image.devicePixelRatio()); + cursorLayer->setHotspot(hotspot); + + std::optional beginInfo = cursorLayer->beginFrame(); + if (!beginInfo) { + return; + } + + const QRect cursorRect(QPoint(0, 0), image.size() / image.devicePixelRatio()); + + QMatrix4x4 mvp; + mvp.ortho(QRect(QPoint(), beginInfo->renderTarget.size())); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + GLTexture texture(image); + texture.bind(); + ShaderBinder binder(ShaderTrait::MapTexture); + binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp); + texture.render(cursorRect, beginInfo->renderTarget.devicePixelRatio()); + texture.unbind(); + glDisable(GL_BLEND); + + cursorLayer->endFrame(infiniteRegion(), infiniteRegion()); +} + +void WaylandOutput::renderCursorQPainter(WaylandQPainterBackend *backend, const QImage &image, const QPoint &hotspot) +{ + WaylandQPainterCursorLayer *cursorLayer = backend->cursorLayer(this); + cursorLayer->setSize(image.size()); + cursorLayer->setScale(image.devicePixelRatio()); + cursorLayer->setHotspot(hotspot); + + std::optional beginInfo = cursorLayer->beginFrame(); + if (!beginInfo) { + return; + } + + const QRect cursorRect(QPoint(0, 0), image.size() / image.devicePixelRatio()); + + QImage *c = std::get(beginInfo->renderTarget.nativeHandle()); + c->setDevicePixelRatio(scale()); + c->fill(Qt::transparent); + + QPainter p; + p.begin(c); + p.setWorldTransform(logicalToNativeMatrix(cursorRect, 1, transform()).toTransform()); + p.setRenderHint(QPainter::SmoothPixmapTransform); + p.drawImage(QPoint(0, 0), image); + p.end(); + + cursorLayer->endFrame(infiniteRegion(), infiniteRegion()); +} + void WaylandOutput::init(const QSize &pixelSize, qreal scale) { m_renderLoop->setRefreshRate(s_refreshRate); diff --git a/src/backends/wayland/wayland_output.h b/src/backends/wayland/wayland_output.h index 12051b95e4..4970b38cc5 100644 --- a/src/backends/wayland/wayland_output.h +++ b/src/backends/wayland/wayland_output.h @@ -32,6 +32,8 @@ namespace KWin namespace Wayland { class WaylandBackend; +class WaylandEglBackend; +class WaylandQPainterBackend; class WaylandCursor { @@ -74,6 +76,7 @@ public: bool isReady() const; KWayland::Client::Surface *surface() const; WaylandCursor *cursor() const; + WaylandBackend *backend() const; void lockPointer(KWayland::Client::Pointer *pointer, bool lock); void resize(const QSize &pixelSize); @@ -84,6 +87,8 @@ public: private: void handleConfigure(const QSize &size, KWayland::Client::XdgShellSurface::States states, quint32 serial); void updateWindowTitle(); + void renderCursorOpengl(WaylandEglBackend *backend, const QImage &image, const QPoint &hotspot); + void renderCursorQPainter(WaylandQPainterBackend *backend, const QImage &image, const QPoint &hotspot); std::unique_ptr m_renderLoop; std::unique_ptr m_surface; diff --git a/src/backends/wayland/wayland_qpainter_backend.cpp b/src/backends/wayland/wayland_qpainter_backend.cpp index 67c3da79f1..cd7868b829 100644 --- a/src/backends/wayland/wayland_qpainter_backend.cpp +++ b/src/backends/wayland/wayland_qpainter_backend.cpp @@ -36,26 +36,19 @@ WaylandQPainterBufferSlot::~WaylandQPainterBufferSlot() buffer->setUsed(false); } -WaylandQPainterOutput::WaylandQPainterOutput(WaylandOutput *output) +WaylandQPainterPrimaryLayer::WaylandQPainterPrimaryLayer(WaylandOutput *output) : m_waylandOutput(output) + , m_pool(output->backend()->display()->shmPool()) { + connect(m_pool, &KWayland::Client::ShmPool::poolResized, this, &WaylandQPainterPrimaryLayer::remapBuffer); } -WaylandQPainterOutput::~WaylandQPainterOutput() +WaylandQPainterPrimaryLayer::~WaylandQPainterPrimaryLayer() { m_slots.clear(); } -bool WaylandQPainterOutput::init(KWayland::Client::ShmPool *pool) -{ - m_pool = pool; - - connect(pool, &KWayland::Client::ShmPool::poolResized, this, &WaylandQPainterOutput::remapBuffer); - - return true; -} - -void WaylandQPainterOutput::remapBuffer() +void WaylandQPainterPrimaryLayer::remapBuffer() { qCDebug(KWIN_WAYLAND_BACKEND) << "Remapped back buffer of surface" << m_waylandOutput->surface(); @@ -65,7 +58,7 @@ void WaylandQPainterOutput::remapBuffer() } } -void WaylandQPainterOutput::present() +void WaylandQPainterPrimaryLayer::present() { for (const auto &slot : m_slots) { if (slot.get() == m_back) { @@ -82,12 +75,12 @@ void WaylandQPainterOutput::present() s->commit(); } -WaylandQPainterBufferSlot *WaylandQPainterOutput::back() const +WaylandQPainterBufferSlot *WaylandQPainterPrimaryLayer::back() const { return m_back; } -WaylandQPainterBufferSlot *WaylandQPainterOutput::acquire() +WaylandQPainterBufferSlot *WaylandQPainterPrimaryLayer::acquire() { const QSize nativeSize(m_waylandOutput->pixelSize()); if (m_swapchainSize != nativeSize) { @@ -116,12 +109,12 @@ WaylandQPainterBufferSlot *WaylandQPainterOutput::acquire() return m_back; } -QRegion WaylandQPainterOutput::accumulateDamage(int bufferAge) const +QRegion WaylandQPainterPrimaryLayer::accumulateDamage(int bufferAge) const { return m_damageJournal.accumulate(bufferAge, infiniteRegion()); } -std::optional WaylandQPainterOutput::beginFrame() +std::optional WaylandQPainterPrimaryLayer::beginFrame() { WaylandQPainterBufferSlot *slot = acquire(); return OutputLayerBeginFrameInfo{ @@ -130,12 +123,71 @@ std::optional WaylandQPainterOutput::beginFrame() }; } -bool WaylandQPainterOutput::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +bool WaylandQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { m_damageJournal.add(damagedRegion); return true; } +WaylandQPainterCursorLayer::WaylandQPainterCursorLayer(WaylandOutput *output) + : m_output(output) +{ +} + +WaylandQPainterCursorLayer::~WaylandQPainterCursorLayer() +{ +} + +qreal WaylandQPainterCursorLayer::scale() const +{ + return m_scale; +} + +void WaylandQPainterCursorLayer::setScale(qreal scale) +{ + m_scale = scale; +} + +QPoint WaylandQPainterCursorLayer::hotspot() const +{ + return m_hotspot; +} + +void WaylandQPainterCursorLayer::setHotspot(const QPoint &hotspot) +{ + m_hotspot = hotspot; +} + +QSize WaylandQPainterCursorLayer::size() const +{ + return m_size; +} + +void WaylandQPainterCursorLayer::setSize(const QSize &size) +{ + m_size = size; +} + +std::optional WaylandQPainterCursorLayer::beginFrame() +{ + const QSize bufferSize = m_size.expandedTo(QSize(64, 64)); + if (m_backingStore.size() != bufferSize) { + m_backingStore = QImage(bufferSize, QImage::Format_ARGB32_Premultiplied); + } + + return OutputLayerBeginFrameInfo{ + .renderTarget = RenderTarget(&m_backingStore), + .repaint = infiniteRegion(), + }; +} + +bool WaylandQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +{ + KWayland::Client::Buffer::Ptr buffer = m_output->backend()->display()->shmPool()->createBuffer(m_backingStore); + m_output->cursor()->update(buffer, m_scale, m_hotspot); + return true; +} + WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b) : QPainterBackend() , m_backend(b) @@ -147,13 +199,7 @@ WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b) } connect(m_backend, &WaylandBackend::outputAdded, this, &WaylandQPainterBackend::createOutput); connect(m_backend, &WaylandBackend::outputRemoved, this, [this](Output *waylandOutput) { - auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [waylandOutput](const auto &output) { - return output->m_waylandOutput == waylandOutput; - }); - if (it == m_outputs.end()) { - return; - } - m_outputs.erase(it); + m_outputs.erase(waylandOutput); }); } @@ -163,19 +209,26 @@ WaylandQPainterBackend::~WaylandQPainterBackend() void WaylandQPainterBackend::createOutput(Output *waylandOutput) { - const auto output = std::make_shared(static_cast(waylandOutput)); - output->init(m_backend->display()->shmPool()); - m_outputs.insert(waylandOutput, output); + m_outputs[waylandOutput] = Layers{ + .primaryLayer = std::make_unique(static_cast(waylandOutput)), + .cursorLayer = std::make_unique(static_cast(waylandOutput)), + }; } void WaylandQPainterBackend::present(Output *output) { - m_outputs[output]->present(); + m_outputs[output].primaryLayer->present(); } OutputLayer *WaylandQPainterBackend::primaryLayer(Output *output) { - return m_outputs[output].get(); -} + return m_outputs[output].primaryLayer.get(); +} + +WaylandQPainterCursorLayer *WaylandQPainterBackend::cursorLayer(Output *output) +{ + return m_outputs[output].cursorLayer.get(); +} + } } diff --git a/src/backends/wayland/wayland_qpainter_backend.h b/src/backends/wayland/wayland_qpainter_backend.h index 7a8a28e6f4..5e63dc6ebb 100644 --- a/src/backends/wayland/wayland_qpainter_backend.h +++ b/src/backends/wayland/wayland_qpainter_backend.h @@ -13,6 +13,8 @@ #include "qpainterbackend.h" #include "utils/damagejournal.h" +#include + #include #include #include @@ -46,16 +48,15 @@ public: int age = 0; }; -class WaylandQPainterOutput : public OutputLayer +class WaylandQPainterPrimaryLayer : public OutputLayer { public: - WaylandQPainterOutput(WaylandOutput *output); - ~WaylandQPainterOutput() override; + WaylandQPainterPrimaryLayer(WaylandOutput *output); + ~WaylandQPainterPrimaryLayer() override; std::optional beginFrame() override; bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; - bool init(KWayland::Client::ShmPool *pool); void remapBuffer(); WaylandQPainterBufferSlot *back() const; @@ -77,6 +78,34 @@ private: friend class WaylandQPainterBackend; }; +class WaylandQPainterCursorLayer : public OutputLayer +{ + Q_OBJECT + +public: + explicit WaylandQPainterCursorLayer(WaylandOutput *output); + ~WaylandQPainterCursorLayer() override; + + qreal scale() const; + void setScale(qreal scale); + + QPoint hotspot() const; + void setHotspot(const QPoint &hotspot); + + QSize size() const; + void setSize(const QSize &size); + + std::optional beginFrame() override; + bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + +private: + WaylandOutput *m_output; + QImage m_backingStore; + QPoint m_hotspot; + QSize m_size; + qreal m_scale = 1.0; +}; + class WaylandQPainterBackend : public QPainterBackend { Q_OBJECT @@ -86,13 +115,20 @@ public: void present(Output *output) override; OutputLayer *primaryLayer(Output *output) override; + WaylandQPainterCursorLayer *cursorLayer(Output *output); private: void createOutput(Output *waylandOutput); void frameRendered(); + struct Layers + { + std::unique_ptr primaryLayer; + std::unique_ptr cursorLayer; + }; + WaylandBackend *m_backend; - QMap> m_outputs; + std::map m_outputs; }; } // namespace Wayland