From 7e412517c4fa10aad6f7bb0b691cb3335e815db0 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Fri, 3 Jul 2020 14:31:17 +0200 Subject: Support wl_surface.damage_buffer Add compositor support for wl_surface.damage_buffer requests. This also required updating wl_compositor to version 4. Fixes: QTBUG-74927 Change-Id: I887ed04e60fe14ecce7df6a517950b0091e2ad54 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../compositor_api/qwaylandcompositor.cpp | 2 +- src/compositor/compositor_api/qwaylandsurface.cpp | 37 ++++++++++++++++- src/compositor/compositor_api/qwaylandsurface_p.h | 2 + tests/auto/compositor/compositor/mockclient.cpp | 2 +- .../auto/compositor/compositor/tst_compositor.cpp | 8 +++- tests/manual/scaling-compositor/main.qml | 47 ++++++++++++++++------ .../scaling-compositor/scaling-compositor.pro | 3 +- 7 files changed, 81 insertions(+), 20 deletions(-) diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 8878ce121..fb99f9413 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -190,7 +190,7 @@ void QWaylandCompositorPrivate::init() if (socketArg != -1 && socketArg + 1 < arguments.size()) socket_name = arguments.at(socketArg + 1).toLocal8Bit(); } - wl_compositor::init(display, 3); + wl_compositor::init(display, 4); wl_subcompositor::init(display, 1); #if QT_CONFIG(wayland_datadevice) diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index 2ebb04a35..efd186fc5 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -195,9 +195,26 @@ void QWaylandSurfacePrivate::surface_attach(Resource *, struct wl_resource *buff pending.newlyAttached = true; } +/* + Note: The Wayland protocol specifies that buffer scale and damage can be interleaved, so + we cannot scale the damage region until commit. We assume that clients will either use + surface_damage or surface_damage_buffer within one frame for one surface. +*/ + void QWaylandSurfacePrivate::surface_damage(Resource *, int32_t x, int32_t y, int32_t width, int32_t height) { + if (Q_UNLIKELY(pending.damageInBufferCoordinates && !pending.damage.isNull())) + qCWarning(qLcWaylandCompositor) << "Unsupported: Client is using both wl_surface.damage_buffer and wl_surface.damage."; + pending.damage = pending.damage.united(QRect(x, y, width, height)); + pending.damageInBufferCoordinates = false; +} + +void QWaylandSurfacePrivate::surface_damage_buffer(Resource *, int32_t x, int32_t y, int32_t width, int32_t height) +{ + if (Q_UNLIKELY(!pending.damageInBufferCoordinates && !pending.damage.isNull())) + qCWarning(qLcWaylandCompositor) << "Unsupported: Client is using both wl_surface.damage_buffer and wl_surface.damage."; pending.damage = pending.damage.united(QRect(x, y, width, height)); + pending.damageInBufferCoordinates = true; } void QWaylandSurfacePrivate::surface_frame(Resource *resource, uint32_t callback) @@ -240,7 +257,24 @@ void QWaylandSurfacePrivate::surface_commit(Resource *) QSize surfaceSize = bufferSize / bufferScale; sourceGeometry = !pending.sourceGeometry.isValid() ? QRect(QPoint(), surfaceSize) : pending.sourceGeometry; destinationSize = pending.destinationSize.isEmpty() ? sourceGeometry.size().toSize() : pending.destinationSize; - damage = pending.damage.intersected(QRect(QPoint(), destinationSize)); + if (!pending.damageInBufferCoordinates || pending.bufferScale == 1) { + // pending.damage is already in surface coordinates + damage = pending.damage.intersected(QRect(QPoint(), destinationSize)); + } else { + // We must transform pending.damage from buffer coordinate system to surface coordinates + // TODO(QTBUG-85461): Also support wp_viewport setting more complex transformations + auto xform = [](const QRect &r, int scale) -> QRect { + QRect res{ + QPoint{ r.x() / scale, r.y() / scale }, + QPoint{ (r.right() + scale - 1) / scale, (r.bottom() + scale - 1) / scale } + }; + return res; + }; + damage = {}; + for (const QRect &r : pending.damage) { + damage |= xform(r, bufferScale).intersected(QRect{{}, destinationSize}); + } + } hasContent = bufferRef.hasContent(); frameCallbacks << pendingFrameCallbacks; inputRegion = pending.inputRegion.intersected(QRect(QPoint(), destinationSize)); @@ -255,6 +289,7 @@ void QWaylandSurfacePrivate::surface_commit(Resource *) pending.offset = QPoint(); pending.newlyAttached = false; pending.damage = QRegion(); + pending.damageInBufferCoordinates = false; pendingFrameCallbacks.clear(); // Notify buffers and views diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h index 3f657c9d0..1150ccf91 100644 --- a/src/compositor/compositor_api/qwaylandsurface_p.h +++ b/src/compositor/compositor_api/qwaylandsurface_p.h @@ -116,6 +116,7 @@ protected: struct wl_resource *buffer, int x, int y) override; void surface_damage(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override; + void surface_damage_buffer(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override; void surface_frame(Resource *resource, uint32_t callback) override; void surface_set_opaque_region(Resource *resource, @@ -141,6 +142,7 @@ public: //member variables struct { QWaylandBufferRef buffer; QRegion damage; + bool damageInBufferCoordinates = false; QPoint offset; bool newlyAttached = false; QRegion inputRegion; diff --git a/tests/auto/compositor/compositor/mockclient.cpp b/tests/auto/compositor/compositor/mockclient.cpp index 76ccd0c58..53e10d687 100644 --- a/tests/auto/compositor/compositor/mockclient.cpp +++ b/tests/auto/compositor/compositor/mockclient.cpp @@ -166,7 +166,7 @@ void MockClient::handleGlobalRemove(void *data, wl_registry *wl_registry, uint32 void MockClient::handleGlobal(uint32_t id, const QByteArray &interface) { if (interface == "wl_compositor") { - compositor = static_cast(wl_registry_bind(registry, id, &wl_compositor_interface, 3)); + compositor = static_cast(wl_registry_bind(registry, id, &wl_compositor_interface, 4)); } else if (interface == "wl_output") { auto output = static_cast(wl_registry_bind(registry, id, &wl_output_interface, 2)); m_outputs.insert(id, output); diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp index a44aef2f3..902f420de 100644 --- a/tests/auto/compositor/compositor/tst_compositor.cpp +++ b/tests/auto/compositor/compositor/tst_compositor.cpp @@ -531,8 +531,6 @@ void tst_WaylandCompositor::mapSurfaceHiDpi() }; QObject::connect(waylandSurface, &QWaylandSurface::damaged, [=] (const QRegion &damage) { - // Currently, QWaylandSurface::size returns the size in pixels. - // Should be fixed or removed for Qt 6. QCOMPARE(damage, QRect(QPoint(), surfaceSize)); verifyComittedState(); }); @@ -570,6 +568,12 @@ void tst_WaylandCompositor::mapSurfaceHiDpi() QTRY_COMPARE(destinationSizeSpy.count(), 1); QTRY_COMPARE(bufferScaleSpy.count(), 1); QTRY_COMPARE(offsetSpy.count(), 1); + QTRY_COMPARE(damagedSpy.count(), 1); + + // Now verify that wl_surface_damage_buffer gets mapped properly + wl_surface_damage_buffer(surface, 0, 0, bufferSize.width(), bufferSize.height()); + wl_surface_commit(surface); + QTRY_COMPARE(damagedSpy.count(), 2); wl_surface_destroy(surface); } diff --git a/tests/manual/scaling-compositor/main.qml b/tests/manual/scaling-compositor/main.qml index 056af4e5b..655bae1c2 100644 --- a/tests/manual/scaling-compositor/main.qml +++ b/tests/manual/scaling-compositor/main.qml @@ -48,10 +48,9 @@ ** ****************************************************************************/ -import QtQuick 2.2 +import QtQuick 2.15 import QtQuick.Window 2.2 -import QtQuick.Controls 2.0 -import QtWayland.Compositor 1.0 +import QtWayland.Compositor 1.3 WaylandCompositor { id: comp @@ -66,16 +65,7 @@ WaylandCompositor { height: 500 visible: true title: "Scaling compositor x" + output.scaleFactor - Button { - id: incrementButton - text: "+" - onClicked: ++output.scaleFactor - } - Button { - text: "-" - onClicked: output.scaleFactor = Math.max(1, output.scaleFactor - 1) - anchors.left: incrementButton.right - } + Repeater { model: shellSurfaces ShellSurfaceItem { @@ -83,6 +73,33 @@ WaylandCompositor { onSurfaceDestroyed: shellSurfaces.remove(index); } } + + Rectangle { + id: incrementButton + color: "#c0f0d0" + Text { + text: "+" + } + width: 100 + height: 30 + TapHandler { + onTapped: ++output.scaleFactor + } + } + + Rectangle { + id: decrementButton + color: "#f0d0c0" + Text { + text: "-" + } + width: 100 + height: 30 + TapHandler { + onTapped: output.scaleFactor = Math.max(1, output.scaleFactor - 1) + } + anchors.left: incrementButton.right + } } } @@ -91,4 +108,8 @@ WaylandCompositor { WlShell { onWlShellSurfaceCreated: shellSurfaces.append({shellSurface: shellSurface}); } + XdgShell { + onToplevelCreated: + shellSurfaces.append({shellSurface: xdgSurface}); + } } diff --git a/tests/manual/scaling-compositor/scaling-compositor.pro b/tests/manual/scaling-compositor/scaling-compositor.pro index 847e07ea7..200dc8c40 100644 --- a/tests/manual/scaling-compositor/scaling-compositor.pro +++ b/tests/manual/scaling-compositor/scaling-compositor.pro @@ -1,7 +1,6 @@ TEMPLATE = app -QT += gui qml quickcontrols2 - +QT += gui qml SOURCES += main.cpp RESOURCES += qml.qrc -- cgit v1.2.3