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: https://phabricator.kde.org/D6186
This commit is contained in:
Oleg Chernovskiy 2017-06-12 23:28:39 +03:00
parent 004c0f3892
commit 247ef43f68
No known key found for this signature in database
GPG key ID: 31CCA288E2976C11
6 changed files with 65 additions and 1 deletions

View file

@ -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);

View file

@ -42,6 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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()) {
return;
}
// 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()) {
return;
}
m_cursorTexture.reset(new GLTexture(img));
};
// init now
updateCursorTexture();
// 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
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// paint texture in cursor offset
m_cursorTexture->bind();
ShaderBinder binder(ShaderTrait::MapTexture);
binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
m_cursorTexture->render(QRegion(cursorRect), cursorRect);
m_cursorTexture->unbind();
kwinApp()->platform()->markCursorAsRendered();
glDisable(GL_BLEND);
}
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;
updateProjectionMatrix();
paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo); // call generic implementation
paintCursor();
GLVertexBuffer::streamingBuffer()->endOfFrame();

View file

@ -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:
private:
LanczosFilter *m_lanczosFilter;
QScopedPointer<GLTexture> m_cursorTexture;
QMatrix4x4 m_projectionMatrix;
QMatrix4x4 m_screenProjectionMatrix;
GLuint vao;

View file

@ -134,10 +134,10 @@ public:
protected:
virtual void paintBackground(QRegion region) override;
virtual Scene::Window *createWindow(Toplevel *toplevel) override;
void paintCursor() override;
private:
explicit SceneQPainter(QPainterBackend *backend, QObject *parent = nullptr);
void paintCursor();
QScopedPointer<QPainterBackend> m_backend;
QScopedPointer<QPainter> m_painter;
class Window;

View file

@ -1296,3 +1296,9 @@ void SceneXRenderDecorationRenderer::reparent(Deleted *deleted)
} // namespace
#endif
void KWin::SceneXrender::paintCursor()
{
}

View file

@ -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;
private:
explicit SceneXrender(XRenderBackend *backend, QObject *parent = nullptr);
static ScreenPaintData screen_paint;