diff --git a/plugins/platforms/drm/drm_backend.h b/plugins/platforms/drm/drm_backend.h --- a/plugins/platforms/drm/drm_backend.h +++ b/plugins/platforms/drm/drm_backend.h @@ -61,6 +61,8 @@ class DrmCrtc; class DrmConnector; +class EglGbmBackend; + class KWIN_EXPORT DrmBackend : public Platform { @@ -166,6 +168,7 @@ QScopedPointer m_dpmsFilter; KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr; gbm_device *m_gbmDevice = nullptr; + friend class EglGbmBackend; }; diff --git a/plugins/platforms/drm/drm_buffer_gbm.cpp b/plugins/platforms/drm/drm_buffer_gbm.cpp --- a/plugins/platforms/drm/drm_buffer_gbm.cpp +++ b/plugins/platforms/drm/drm_buffer_gbm.cpp @@ -18,6 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ + +#include + #include "drm_backend.h" #include "drm_buffer_gbm.h" diff --git a/plugins/platforms/drm/egl_gbm_backend.cpp b/plugins/platforms/drm/egl_gbm_backend.cpp --- a/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/plugins/platforms/drm/egl_gbm_backend.cpp @@ -155,16 +155,10 @@ void EglGbmBackend::initRemotePresent() { - bool supportRemotePresent = false; - const QByteArray remoteOption = qgetenv("KWIN_REMOTE"); - - if (!remoteOption.isEmpty()) { - supportRemotePresent = remoteOption == QByteArrayLiteral("1"); - } - - if(supportRemotePresent) { + if(qEnvironmentVariableIsSet("KWIN_REMOTE")) { qCDebug(KWIN_DRM) << "Support for remote present enabled"; m_remoteaccessManager.reset(new RemoteAccessManager); + m_backend->setSoftWareCursor(true); } } diff --git a/scene_opengl.h b/scene_opengl.h --- a/scene_opengl.h +++ b/scene_opengl.h @@ -100,6 +100,7 @@ virtual void doPaintBackground(const QVector &vertices) = 0; virtual void updateProjectionMatrix() = 0; + virtual void paintCursor(); Q_SIGNALS: void resetCompositing(); @@ -137,6 +138,7 @@ virtual Scene::Window *createWindow(Toplevel *t); virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data); virtual void updateProjectionMatrix() override; + virtual void paintCursor() override; private Q_SLOTS: void resetLanczosFilter(); @@ -147,6 +149,7 @@ private: LanczosFilter *m_lanczosFilter; + QScopedPointer m_cursorTexture; QMatrix4x4 m_projectionMatrix; QMatrix4x4 m_screenProjectionMatrix; GLuint vao; diff --git a/scene_opengl.cpp b/scene_opengl.cpp --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -42,6 +42,7 @@ #include "main.h" #include "overlaywindow.h" #include "screens.h" +#include "cursor.h" #include "decorations/decoratedclient.h" #include @@ -678,6 +679,61 @@ } } +void SceneOpenGL::paintCursor() +{ + +} + +/** + * 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; + } + + // don't paint if no image for cursor is set + const QImage img = kwinApp()->platform()->softwareCursor(); + if (img.isNull()) { + return; + } + + // lazy init texture cursor only in case we need software rendering + if (!m_cursorTexture) { + m_cursorTexture.reset(new GLTexture(img)); + + // handle shape update in case cursor image changed + connect(Cursor::self(), &Cursor::cursorChanged, this, [this] { + const QImage img = kwinApp()->platform()->softwareCursor(); + m_cursorTexture.reset(new GLTexture(img)); + }); + } + + // 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 +767,7 @@ int mask = 0; updateProjectionMatrix(); paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo); // call generic implementation + paintCursor(); GLVertexBuffer::streamingBuffer()->endOfFrame();