Skip to content

Commit d949f91

Browse files
committed
wayland/screencopy: apply output transform to wlr screencopy
Note that this only fixes output copies, and not toplevel copies. Toplevel copies are harder because a toplevel can be on more than one output. Hopefully we'll all be using image-copy-capture before this one comes up. Fixes #75
1 parent 27f97c3 commit d949f91

File tree

4 files changed

+103
-8
lines changed

4 files changed

+103
-8
lines changed

src/wayland/buffer/manager.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct WlBufferTransform {
4040

4141
[[nodiscard]] int degrees() const { return 90 * (this->transform & 0b11111011); }
4242
[[nodiscard]] bool flip() const { return this->transform & 0b00000100; }
43+
[[nodiscard]] bool flipSize() const { return this->transform & 0b00000001; }
4344

4445
void apply(QMatrix4x4& matrix) const {
4546
matrix.rotate(this->flip() ? 180 : 0, 0, 1, 0);

src/wayland/screencopy/view.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,14 @@ void ScreencopyView::captureFrame() {
120120
void ScreencopyView::onFrameCaptured() {
121121
this->setFlag(QQuickItem::ItemHasContents);
122122
this->update();
123+
124+
const auto& frontbuffer = this->context->swapchain().frontbuffer();
125+
126+
auto size = frontbuffer->size();
127+
if (frontbuffer->transform.flipSize()) size.transpose();
128+
129+
this->bSourceSize = size;
123130
this->bHasContent = true;
124-
this->bSourceSize = this->context->swapchain().frontbuffer()->size();
125131
}
126132

127133
void ScreencopyView::componentComplete() {

src/wayland/screencopy/wlr_screencopy/wlr_screencopy.cpp

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#include "wlr_screencopy.hpp"
22
#include <cstdint>
33

4+
#include <private/qwaylanddisplay_p.h>
45
#include <private/qwaylandscreen_p.h>
56
#include <qlogging.h>
67
#include <qloggingcategory.h>
78
#include <qobject.h>
89
#include <qscreen.h>
910
#include <qtmetamacros.h>
11+
#include <qtypes.h>
1012
#include <qwaylandclientextension.h>
1113
#include <wayland-wlr-screencopy-unstable-v1-client-protocol.h>
1214

@@ -45,6 +47,7 @@ WlrScreencopyContext::WlrScreencopyContext(
4547
, screen(dynamic_cast<QtWaylandClient::QWaylandScreen*>(screen->handle()))
4648
, paintCursors(paintCursors)
4749
, region(region) {
50+
this->transform.setScreen(this->screen);
4851
QObject::connect(screen, &QObject::destroyed, this, &WlrScreencopyContext::onScreenDestroyed);
4952
}
5053

@@ -99,9 +102,7 @@ void WlrScreencopyContext::zwlr_screencopy_frame_v1_linux_dmabuf(
99102
}
100103

101104
void WlrScreencopyContext::zwlr_screencopy_frame_v1_flags(uint32_t flags) {
102-
if (flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT) {
103-
this->mSwapchain.backbuffer()->transform = buffer::WlBufferTransform::Flipped180;
104-
}
105+
this->yInvert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
105106
}
106107

107108
void WlrScreencopyContext::zwlr_screencopy_frame_v1_buffer_done() {
@@ -119,15 +120,69 @@ void WlrScreencopyContext::zwlr_screencopy_frame_v1_ready(
119120
uint32_t /*tvSecLo*/,
120121
uint32_t /*tvNsec*/
121122
) {
122-
this->destroy();
123-
this->copiedFirstFrame = true;
124-
this->mSwapchain.swapBuffers();
125-
emit this->frameCaptured();
123+
this->submitFrame();
126124
}
127125

128126
void WlrScreencopyContext::zwlr_screencopy_frame_v1_failed() {
129127
qCWarning(logScreencopy) << "Ending recording due to screencopy failure for" << this;
130128
emit this->stopped();
131129
}
132130

131+
void WlrScreencopyContext::updateTransform(bool previouslyUnset) {
132+
if (previouslyUnset && this->copiedFirstFrame) this->submitFrame();
133+
}
134+
135+
void WlrScreencopyContext::submitFrame() {
136+
this->copiedFirstFrame = true;
137+
if (this->transform.transform == -1) return;
138+
139+
auto flipTransform =
140+
this->yInvert ? buffer::WlBufferTransform::Flipped180 : buffer::WlBufferTransform::Normal0;
141+
142+
this->mSwapchain.backbuffer()->transform = this->transform.transform ^ flipTransform;
143+
144+
this->destroy();
145+
this->mSwapchain.swapBuffers();
146+
emit this->frameCaptured();
147+
}
148+
149+
WlrScreencopyContext::OutputTransformQuery::OutputTransformQuery(WlrScreencopyContext* context)
150+
: context(context) {}
151+
152+
WlrScreencopyContext::OutputTransformQuery::~OutputTransformQuery() {
153+
if (this->isInitialized()) this->release();
154+
}
155+
156+
void WlrScreencopyContext::OutputTransformQuery::setScreen(QtWaylandClient::QWaylandScreen* screen
157+
) {
158+
// cursed hack
159+
class QWaylandScreenReflector: public QtWaylandClient::QWaylandScreen {
160+
public:
161+
[[nodiscard]] int globalId() const { return this->m_outputId; }
162+
};
163+
164+
if (this->isInitialized()) this->release();
165+
166+
this->init(
167+
screen->display()->wl_registry(),
168+
static_cast<QWaylandScreenReflector*>(screen)->globalId(), // NOLINT
169+
3
170+
);
171+
}
172+
173+
void WlrScreencopyContext::OutputTransformQuery::output_geometry(
174+
qint32 /*x*/,
175+
qint32 /*y*/,
176+
qint32 /*width*/,
177+
qint32 /*height*/,
178+
qint32 /*subpixel*/,
179+
const QString& /*make*/,
180+
const QString& /*model*/,
181+
qint32 transform
182+
) {
183+
auto newTransform = this->transform == -1;
184+
this->transform = transform;
185+
this->context->updateTransform(newTransform);
186+
}
187+
133188
} // namespace qs::wayland::screencopy::wlr

src/wayland/screencopy/wlr_screencopy/wlr_screencopy_p.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#pragma once
22

3+
#include <private/qwayland-wayland.h>
34
#include <private/qwaylandscreen_p.h>
5+
#include <qcontainerfwd.h>
46
#include <qtclasshelpermacros.h>
7+
#include <qtypes.h>
58
#include <qwayland-wlr-screencopy-unstable-v1.h>
69

710
#include "../manager.hpp"
@@ -24,6 +27,7 @@ class WlrScreencopyContext
2427
Q_DISABLE_COPY_MOVE(WlrScreencopyContext);
2528

2629
void captureFrame() override;
30+
void updateTransform(bool previouslyUnset);
2731

2832
protected:
2933
// clang-format off
@@ -39,9 +43,38 @@ private slots:
3943
void onScreenDestroyed();
4044

4145
private:
46+
void submitFrame();
47+
48+
class OutputTransformQuery: public QtWayland::wl_output {
49+
public:
50+
OutputTransformQuery(WlrScreencopyContext* context);
51+
~OutputTransformQuery() override;
52+
Q_DISABLE_COPY_MOVE(OutputTransformQuery);
53+
54+
qint32 transform = -1;
55+
void setScreen(QtWaylandClient::QWaylandScreen* screen);
56+
57+
protected:
58+
void output_geometry(
59+
qint32 x,
60+
qint32 y,
61+
qint32 width,
62+
qint32 height,
63+
qint32 subpixel,
64+
const QString& make,
65+
const QString& model,
66+
qint32 transform
67+
) override;
68+
69+
private:
70+
WlrScreencopyContext* context;
71+
};
72+
4273
WlrScreencopyManager* manager;
4374
buffer::WlBufferRequest request;
4475
bool copiedFirstFrame = false;
76+
OutputTransformQuery transform {this};
77+
bool yInvert = false;
4578

4679
QtWaylandClient::QWaylandScreen* screen;
4780
bool paintCursors;

0 commit comments

Comments
 (0)