diff --git a/CMakeLists.txt b/CMakeLists.txt index 48ab676e7b..fcd72dc541 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,6 +278,7 @@ find_package(XCB 1.10 REQUIRED COMPONENTS ICCCM IMAGE KEYSYMS + PRESENT RANDR RENDER SHAPE diff --git a/src/backends/x11/windowed/CMakeLists.txt b/src/backends/x11/windowed/CMakeLists.txt index 834d3838db..be3c5326fd 100644 --- a/src/backends/x11/windowed/CMakeLists.txt +++ b/src/backends/x11/windowed/CMakeLists.txt @@ -6,7 +6,11 @@ target_sources(kwin PRIVATE x11_windowed_qpainter_backend.cpp ) -target_link_libraries(kwin X11::XCB X11::X11) +target_link_libraries(kwin + X11::XCB + X11::X11 + XCB::PRESENT +) if (X11_Xi_FOUND) target_link_libraries(kwin X11::Xi) endif() diff --git a/src/backends/x11/windowed/x11_windowed_backend.cpp b/src/backends/x11/windowed/x11_windowed_backend.cpp index 2278142e26..7c65dffa71 100644 --- a/src/backends/x11/windowed/x11_windowed_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_backend.cpp @@ -25,11 +25,11 @@ #include // xcb #include +#include // X11 #include #include #if HAVE_X11_XINPUT -#include "../common/ge_event_mem_mover.h" #include #include #endif @@ -193,6 +193,24 @@ bool X11WindowedBackend::initialize() m_screen = it.data; } } + + const xcb_query_extension_reply_t *presentExtension = xcb_get_extension_data(m_connection, &xcb_present_id); + if (presentExtension && presentExtension->present) { + m_presentOpcode = presentExtension->major_opcode; + xcb_present_query_version_cookie_t cookie = xcb_present_query_version(m_connection, 1, 2); + xcb_present_query_version_reply_t *reply = xcb_present_query_version_reply(m_connection, cookie, nullptr); + if (!reply) { + qCWarning(KWIN_X11WINDOWED) << "Requested Present extension version is unsupported"; + return false; + } + m_presentMajorVersion = reply->major_version; + m_presentMinorVersion = reply->minor_version; + free(reply); + } else { + qCWarning(KWIN_X11WINDOWED) << "Present X11 extension is unavailable"; + return false; + } + initXInput(); XRenderUtils::init(m_connection, m_screen->root); createOutputs(); @@ -365,43 +383,15 @@ void X11WindowedBackend::handleEvent(xcb_generic_event_t *e) xcb_refresh_keyboard_mapping(m_keySymbols, reinterpret_cast(e)); } break; -#if HAVE_X11_XINPUT case XCB_GE_GENERIC: { - GeEventMemMover ge(e); - auto te = reinterpret_cast(e); - const X11WindowedOutput *output = findOutput(te->event); - if (!output) { - break; - } - - const QPointF position = output->mapFromGlobal(QPointF(fixed1616ToReal(te->root_x), fixed1616ToReal(te->root_y))); - - switch (ge->event_type) { - - case XI_TouchBegin: { - Q_EMIT m_touchDevice->touchDown(te->detail, position, te->time, m_touchDevice.get()); - Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); - break; - } - case XI_TouchUpdate: { - Q_EMIT m_touchDevice->touchMotion(te->detail, position, te->time, m_touchDevice.get()); - Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); - break; - } - case XI_TouchEnd: { - Q_EMIT m_touchDevice->touchUp(te->detail, te->time, m_touchDevice.get()); - Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); - break; - } - case XI_TouchOwnership: { - auto te = reinterpret_cast(e); - XIAllowTouchEvents(m_display, te->deviceid, te->sourceid, te->touchid, XIAcceptTouch); - break; - } + xcb_ge_generic_event_t *ev = reinterpret_cast(e); + if (ev->extension == m_presentOpcode) { + handlePresentEvent(ev); + } else if (ev->extension == m_xiOpcode) { + handleXinputEvent(ev); } break; } -#endif default: break; } @@ -558,6 +548,55 @@ void X11WindowedBackend::updateSize(xcb_configure_notify_event_t *event) } } +void X11WindowedBackend::handleXinputEvent(xcb_ge_generic_event_t *ge) +{ +#if HAVE_X11_XINPUT + auto te = reinterpret_cast(ge); + const X11WindowedOutput *output = findOutput(te->event); + if (!output) { + return; + } + + const QPointF position = output->mapFromGlobal(QPointF(fixed1616ToReal(te->root_x), fixed1616ToReal(te->root_y))); + + switch (ge->event_type) { + case XI_TouchBegin: { + Q_EMIT m_touchDevice->touchDown(te->detail, position, te->time, m_touchDevice.get()); + Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); + break; + } + case XI_TouchUpdate: { + Q_EMIT m_touchDevice->touchMotion(te->detail, position, te->time, m_touchDevice.get()); + Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); + break; + } + case XI_TouchEnd: { + Q_EMIT m_touchDevice->touchUp(te->detail, te->time, m_touchDevice.get()); + Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); + break; + } + case XI_TouchOwnership: { + auto te = reinterpret_cast(ge); + XIAllowTouchEvents(m_display, te->deviceid, te->sourceid, te->touchid, XIAcceptTouch); + break; + } + } +#endif +} + +void X11WindowedBackend::handlePresentEvent(xcb_ge_generic_event_t *ge) +{ + switch (ge->event_type) { + case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: { + xcb_present_complete_notify_event_t *completeNotify = reinterpret_cast(ge); + if (X11WindowedOutput *output = findOutput(completeNotify->window)) { + output->handlePresentCompleteNotify(completeNotify); + } + break; + } + } +} + xcb_window_t X11WindowedBackend::rootWindow() const { if (!m_screen) { diff --git a/src/backends/x11/windowed/x11_windowed_backend.h b/src/backends/x11/windowed/x11_windowed_backend.h index 9aa1951e4c..302b9aeafb 100644 --- a/src/backends/x11/windowed/x11_windowed_backend.h +++ b/src/backends/x11/windowed/x11_windowed_backend.h @@ -124,6 +124,8 @@ private: void handleClientMessage(xcb_client_message_event_t *event); void handleButtonPress(xcb_button_press_event_t *event); void handleExpose(xcb_expose_event_t *event); + void handleXinputEvent(xcb_ge_generic_event_t *event); + void handlePresentEvent(xcb_ge_generic_event_t *event); void updateSize(xcb_configure_notify_event_t *event); void initXInput(); X11WindowedOutput *findOutput(xcb_window_t window) const; @@ -149,6 +151,10 @@ private: int m_majorVersion = 0; int m_minorVersion = 0; + int m_presentOpcode = 0; + int m_presentMajorVersion = 0; + int m_presentMinorVersion = 0; + QVector m_outputs; }; diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp index e6ace1bcac..106408cebf 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp @@ -10,7 +10,6 @@ // kwin #include "basiceglsurfacetexture_internal.h" #include "basiceglsurfacetexture_wayland.h" -#include "softwarevsyncmonitor.h" #include "x11_windowed_backend.h" #include "x11_windowed_output.h" // kwin libs @@ -177,8 +176,6 @@ bool X11WindowedEglBackend::createSurfaces() void X11WindowedEglBackend::present(Output *output) { - static_cast(output)->vsyncMonitor()->arm(); - const auto &renderOutput = m_outputs[output]; presentSurface(renderOutput.primaryLayer->surface(), renderOutput.primaryLayer->lastDamage(), output->geometry()); } diff --git a/src/backends/x11/windowed/x11_windowed_output.cpp b/src/backends/x11/windowed/x11_windowed_output.cpp index 44cdb98646..6d6ab495fa 100644 --- a/src/backends/x11/windowed/x11_windowed_output.cpp +++ b/src/backends/x11/windowed/x11_windowed_output.cpp @@ -15,7 +15,6 @@ #include "core/renderloop_p.h" #include "composite.h" -#include "softwarevsyncmonitor.h" #include "x11_windowed_backend.h" #include @@ -90,7 +89,6 @@ void X11WindowedCursor::update(const QImage &image, const QPoint &hotspot) X11WindowedOutput::X11WindowedOutput(X11WindowedBackend *backend) : Output(backend) , m_renderLoop(std::make_unique()) - , m_vsyncMonitor(SoftwareVsyncMonitor::create()) , m_backend(backend) { m_window = xcb_generate_id(m_backend->connection()); @@ -100,12 +98,11 @@ X11WindowedOutput::X11WindowedOutput(X11WindowedBackend *backend) setInformation(Information{ .name = QStringLiteral("X11-%1").arg(identifier), }); - - connect(m_vsyncMonitor.get(), &VsyncMonitor::vblankOccurred, this, &X11WindowedOutput::vblank); } X11WindowedOutput::~X11WindowedOutput() { + xcb_present_select_input(m_backend->connection(), m_presentEvent, m_window, 0); xcb_unmap_window(m_backend->connection(), m_window); xcb_destroy_window(m_backend->connection(), m_window); xcb_flush(m_backend->connection()); @@ -131,11 +128,6 @@ RenderLoop *X11WindowedOutput::renderLoop() const return m_renderLoop.get(); } -SoftwareVsyncMonitor *X11WindowedOutput::vsyncMonitor() const -{ - return m_vsyncMonitor.get(); -} - X11WindowedBackend *X11WindowedOutput::backend() const { return m_backend; @@ -160,7 +152,6 @@ void X11WindowedOutput::init(const QSize &pixelSize, qreal scale) { const int refreshRate = 60000; // TODO: get refresh rate via randr m_renderLoop->setRefreshRate(refreshRate); - m_vsyncMonitor->setRefreshRate(refreshRate); auto mode = std::make_shared(pixelSize, m_renderLoop->refreshRate()); @@ -199,6 +190,10 @@ void X11WindowedOutput::init(const QSize &pixelSize, qreal scale) // select xinput 2 events initXInputForWindow(); + const uint32_t presentEventMask = XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY; + m_presentEvent = xcb_generate_id(m_backend->connection()); + xcb_present_select_input(m_backend->connection(), m_presentEvent, m_window, presentEventMask); + m_winInfo = std::make_unique(m_backend->connection(), m_window, m_backend->screen()->root, NET::WMWindowType, NET::Properties2()); @@ -256,6 +251,12 @@ void X11WindowedOutput::resize(const QSize &pixelSize) setState(next); } +void X11WindowedOutput::handlePresentCompleteNotify(xcb_present_complete_notify_event_t *event) +{ + std::chrono::microseconds timestamp(event->ust); + RenderLoopPrivate::get(m_renderLoop.get())->notifyFrameCompleted(timestamp); +} + void X11WindowedOutput::setWindowTitle(const QString &title) { m_winInfo->setName(title.toUtf8().constData()); @@ -276,12 +277,6 @@ QPointF X11WindowedOutput::mapFromGlobal(const QPointF &pos) const return (pos - hostPosition() + internalPosition()) / scale(); } -void X11WindowedOutput::vblank(std::chrono::nanoseconds timestamp) -{ - RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_renderLoop.get()); - renderLoopPrivate->notifyFrameCompleted(timestamp); -} - bool X11WindowedOutput::setCursor(const QImage &image, const QPoint &hotspot) { if (X11WindowedEglBackend *backend = qobject_cast(Compositor::self()->backend())) { diff --git a/src/backends/x11/windowed/x11_windowed_output.h b/src/backends/x11/windowed/x11_windowed_output.h index 64ba861d20..89cbf05e22 100644 --- a/src/backends/x11/windowed/x11_windowed_output.h +++ b/src/backends/x11/windowed/x11_windowed_output.h @@ -16,13 +16,13 @@ #include #include +#include class NETWinInfo; namespace KWin { -class SoftwareVsyncMonitor; class X11WindowedBackend; class X11WindowedOutput; class X11WindowedEglBackend; @@ -52,7 +52,6 @@ public: ~X11WindowedOutput() override; RenderLoop *renderLoop() const override; - SoftwareVsyncMonitor *vsyncMonitor() const; void init(const QSize &pixelSize, qreal scale); void resize(const QSize &pixelSize); @@ -81,16 +80,17 @@ public: void updateEnabled(bool enabled); + void handlePresentCompleteNotify(xcb_present_complete_notify_event_t *event); + private: void initXInputForWindow(); - void vblank(std::chrono::nanoseconds timestamp); void renderCursorOpengl(X11WindowedEglBackend *backend, const QImage &image, const QPoint &hotspot); void renderCursorQPainter(X11WindowedQPainterBackend *backend, const QImage &image, const QPoint &hotspot); xcb_window_t m_window = XCB_WINDOW_NONE; + xcb_present_event_t m_presentEvent = XCB_NONE; std::unique_ptr m_winInfo; std::unique_ptr m_renderLoop; - std::unique_ptr m_vsyncMonitor; std::unique_ptr m_cursor; QPoint m_hostPosition; QRegion m_exposedArea; diff --git a/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp b/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp index f83367bf42..935c397141 100644 --- a/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_qpainter_backend.cpp @@ -7,7 +7,6 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #include "x11_windowed_qpainter_backend.h" -#include "softwarevsyncmonitor.h" #include "x11_windowed_backend.h" #include "x11_windowed_output.h" @@ -128,7 +127,6 @@ void X11WindowedQPainterBackend::removeOutput(Output *output) void X11WindowedQPainterBackend::present(Output *output) { - static_cast(output)->vsyncMonitor()->arm(); const auto &rendererOutput = m_outputs[output]; xcb_connection_t *c = m_backend->connection();