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:
parent
004c0f3892
commit
247ef43f68
6 changed files with 65 additions and 1 deletions
2
scene.h
2
scene.h
|
@ -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 <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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1296,3 +1296,9 @@ void SceneXRenderDecorationRenderer::reparent(Deleted *deleted)
|
|||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
|
||||
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 ®ion, ScreenPaintData &data);
|
||||
void paintCursor() override;
|
||||
private:
|
||||
explicit SceneXrender(XRenderBackend *backend, QObject *parent = nullptr);
|
||||
static ScreenPaintData screen_paint;
|
||||
|
|
Loading…
Reference in a new issue