Implement software cursor in OpenGL backend

This change is needed for Wayland screen recording apps to work
correctly. With this change the cursor is actually visible using GBM
buffer passing protocol.

Previously OpenGL backend did not support software cursor. If launching
in DRM/OpenGL mode with flicked on software cursor it only rendered
scene, but not the cursor image.

Differential Revision:
parent 004c0f38
......@@ -174,6 +174,8 @@ protected:
// shared implementation, starts painting the screen
void paintScreen(int *mask, const QRegion &damage, const QRegion &repaint,
QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection = QMatrix4x4(), const QRect &outputGeometry = QRect());
// Render cursor texture in case hardware cursor is disabled/non-applicable
virtual void paintCursor() = 0;
friend class EffectsHandlerImpl;
// called after all effects had their paintScreen() called
void finalPaintScreen(int mask, QRegion region, ScreenPaintData& data);
......@@ -42,6 +42,7 @@ along with this program. If not, see <>.
#include "main.h"
#include "overlaywindow.h"
#include "screens.h"
#include "cursor.h"
#include "decorations/decoratedclient.h"
#include <KWayland/Server/subcompositor_interface.h>
......@@ -678,6 +679,57 @@ void SceneOpenGL::insertWait()
* Render cursor texture in case hardware cursor is disabled.
* Useful for screen recording apps or backends that can't do planes.
void SceneOpenGL2::paintCursor()
// don't paint if we use hardware cursor
if (!kwinApp()->platform()->usesSoftwareCursor()) {
// lazy init texture cursor only in case we need software rendering
if (!m_cursorTexture) {
auto updateCursorTexture = [this] {
// don't paint if no image for cursor is set
const QImage img = kwinApp()->platform()->softwareCursor();
if (img.isNull()) {
m_cursorTexture.reset(new GLTexture(img));
// init now
// handle shape update on case cursor image changed
connect(Cursor::self(), &Cursor::cursorChanged, this, updateCursorTexture);
// get cursor position in projection coordinates
const QPoint cursorPos = Cursor::pos() - kwinApp()->platform()->softwareCursorHotspot();
const QRect cursorRect(0, 0, m_cursorTexture->width(), m_cursorTexture->height());
QMatrix4x4 mvp = m_projectionMatrix;
mvp.translate(cursorPos.x(), cursorPos.y());
// handle transparence
// paint texture in cursor offset
ShaderBinder binder(ShaderTrait::MapTexture);
binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
m_cursorTexture->render(QRegion(cursorRect), cursorRect);
qint64 SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
// actually paint the frame, flushed with the NEXT frame
......@@ -711,6 +763,7 @@ qint64 SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
int mask = 0;
paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo); // call generic implementation
......@@ -137,6 +137,7 @@ protected:
virtual Scene::Window *createWindow(Toplevel *t);
virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
virtual void updateProjectionMatrix() override;
void paintCursor() override;
private Q_SLOTS:
void resetLanczosFilter();
......@@ -147,6 +148,7 @@ private:
LanczosFilter *m_lanczosFilter;
QScopedPointer<GLTexture> m_cursorTexture;
QMatrix4x4 m_projectionMatrix;
QMatrix4x4 m_screenProjectionMatrix;
GLuint vao;
......@@ -134,10 +134,10 @@ public:
virtual void paintBackground(QRegion region) override;
virtual Scene::Window *createWindow(Toplevel *toplevel) override;
void paintCursor() override;
explicit SceneQPainter(QPainterBackend *backend, QObject *parent = nullptr);
void paintCursor();
QScopedPointer<QPainterBackend> m_backend;
QScopedPointer<QPainter> m_painter;
class Window;
......@@ -1296,3 +1296,9 @@ void SceneXRenderDecorationRenderer::reparent(Deleted *deleted)
} // namespace
void KWin::SceneXrender::paintCursor()
......@@ -179,6 +179,7 @@ protected:
virtual void paintBackground(QRegion region);
virtual void paintGenericScreen(int mask, ScreenPaintData data);
virtual void paintDesktop(int desktop, int mask, const QRegion &region, ScreenPaintData &data);
void paintCursor() override;
explicit SceneXrender(XRenderBackend *backend, QObject *parent = nullptr);
static ScreenPaintData screen_paint;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment