KWin
Loading...
Searching...
No Matches
compositor.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "compositor.h"
10
11#include <config-kwin.h>
12
13#include "core/output.h"
14#include "core/outputlayer.h"
15#include "core/renderbackend.h"
16#include "core/renderlayer.h"
17#include "core/renderloop.h"
18#include "cursor.h"
19#include "dbusinterface.h"
20#include "ftrace.h"
21#include "scene/cursorscene.h"
22#include "scene/surfaceitem.h"
25#include "utils/common.h"
26#include "wayland/surface.h"
27#include "wayland_server.h"
28#include "window.h"
29#include "workspace.h"
30
31#include <KLocalizedString>
32#if KWIN_BUILD_NOTIFICATIONS
33#include <KNotification>
34#endif
35
36namespace KWin
37{
38
39Compositor *Compositor::s_compositor = nullptr;
44
46 : QObject(workspace)
47{
48 // 2 sec which should be enough to restart the compositor.
49 static const int compositorLostMessageDelay = 2000;
50
51 m_unusedSupportPropertyTimer.setInterval(compositorLostMessageDelay);
52 m_unusedSupportPropertyTimer.setSingleShot(true);
53 connect(&m_unusedSupportPropertyTimer, &QTimer::timeout,
55
56 // Delay the call to start by one event cycle.
57 // The ctor of this class is invoked from the Workspace ctor, that means before
58 // Workspace is completely constructed, so calling Workspace::self() would result
59 // in undefined behavior. This is fixed by using a delayed invocation.
60 QTimer::singleShot(0, this, &Compositor::start);
61
62 // register DBus
64 FTraceLogger::create();
65}
66
72
74{
75 const auto outputs = workspace()->outputs();
76 for (Output *output : outputs) {
77 if (output->renderLoop() == loop) {
78 return output;
79 }
80 }
81 return nullptr;
82}
83
85{
86 m_superlayers.insert(layer->loop(), layer);
87 connect(layer->loop(), &RenderLoop::frameRequested, this, &Compositor::handleFrameRequested);
88}
89
91{
92 m_superlayers.remove(layer->loop());
93 disconnect(layer->loop(), &RenderLoop::frameRequested, this, &Compositor::handleFrameRequested);
94 delete layer;
95}
96
98{
99 m_unusedSupportProperties.removeAll(atom);
100}
101
103{
106}
107
109{
111 // Currently still maybe restarting the compositor.
113 return;
114 }
115 if (auto *con = kwinApp()->x11Connection()) {
116 for (const xcb_atom_t &atom : std::as_const(m_unusedSupportProperties)) {
117 // remove property from root window
118 xcb_delete_property(con, kwinApp()->x11RootWindow(), atom);
119 }
121 }
122}
123
125{
126 // Restart compositing
127 stop();
128 start();
129}
130
131void Compositor::handleFrameRequested(RenderLoop *renderLoop)
132{
133 composite(renderLoop);
134}
135
137{
138 if (m_backend->checkGraphicsReset()) {
139 qCDebug(KWIN_CORE) << "Graphics reset occurred";
140#if KWIN_BUILD_NOTIFICATIONS
141 KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset"));
142#endif
143 reinitialize();
144 return;
145 }
146
147 Output *output = findOutput(renderLoop);
148 OutputLayer *primaryLayer = m_backend->primaryLayer(output);
149 fTraceDuration("Paint (", output->name(), ")");
150
151 RenderLayer *superLayer = m_superlayers[renderLoop];
152 superLayer->setOutputLayer(primaryLayer);
153
154 renderLoop->prepareNewFrame();
155 auto frame = std::make_shared<OutputFrame>(renderLoop);
156
157 if (primaryLayer->needsRepaint() || superLayer->needsRepaint()) {
158 renderLoop->beginPaint();
159
160 QRegion surfaceDamage = primaryLayer->repaints();
161 primaryLayer->resetRepaints();
162 prePaintPass(superLayer, &surfaceDamage);
163
164 Window *const activeWindow = workspace()->activeWindow();
165 SurfaceItem *const activeFullscreenItem = activeWindow && activeWindow->isFullScreen() ? activeWindow->surfaceItem() : nullptr;
166 frame->setContentType(activeWindow && activeFullscreenItem ? activeFullscreenItem->contentType() : ContentType::None);
167
168 const bool wantsAdaptiveSync = activeWindow && activeWindow->wantsAdaptiveSync();
169 const bool vrr = (output->capabilities() & Output::Capability::Vrr) && (output->vrrPolicy() == VrrPolicy::Always || (output->vrrPolicy() == VrrPolicy::Automatic && wantsAdaptiveSync));
170 const bool tearing = (output->capabilities() & Output::Capability::Tearing) && options->allowTearing() && activeFullscreenItem && activeFullscreenItem->presentationHint() == PresentationModeHint::Async;
171 if (vrr) {
172 frame->setPresentationMode(tearing ? PresentationMode::AdaptiveAsync : PresentationMode::AdaptiveSync);
173 } else {
174 frame->setPresentationMode(tearing ? PresentationMode::Async : PresentationMode::VSync);
175 }
176
177 bool directScanout = false;
178 if (const auto scanoutCandidate = superLayer->delegate()->scanoutCandidate()) {
179 const auto sublayers = superLayer->sublayers();
180 const bool scanoutPossible = std::none_of(sublayers.begin(), sublayers.end(), [](RenderLayer *sublayer) {
181 return sublayer->isVisible();
182 });
183 if (scanoutPossible && !output->directScanoutInhibited()) {
184 directScanout = primaryLayer->scanout(scanoutCandidate);
185 }
186 }
187
188 if (!directScanout) {
189 if (auto beginInfo = primaryLayer->beginFrame()) {
190 auto &[renderTarget, repaint] = beginInfo.value();
191
192 const QRegion bufferDamage = surfaceDamage.united(repaint).intersected(superLayer->rect().toAlignedRect());
193
194 paintPass(superLayer, renderTarget, bufferDamage);
195 primaryLayer->endFrame(bufferDamage, surfaceDamage);
196 }
197 }
198
199 postPaintPass(superLayer);
200 }
201
202 m_backend->present(output, frame);
203
204 framePass(superLayer, frame.get());
205
206 // TODO: Put it inside the cursor layer once the cursor layer can be backed by a real output layer.
207 if (waylandServer()) {
208 const std::chrono::milliseconds frameTime =
209 std::chrono::duration_cast<std::chrono::milliseconds>(output->renderLoop()->lastPresentationTimestamp());
210
211 if (!Cursors::self()->isCursorHidden()) {
212 Cursor *cursor = Cursors::self()->currentCursor();
213 if (cursor->geometry().intersects(output->geometry())) {
214 cursor->markAsRendered(frameTime);
215 }
216 }
217 }
218}
219
221{
222 layer->delegate()->frame(frame);
223 const auto sublayers = layer->sublayers();
224 for (RenderLayer *sublayer : sublayers) {
225 framePass(sublayer, frame);
226 }
227}
228
229void Compositor::prePaintPass(RenderLayer *layer, QRegion *damage)
230{
231 if (const QRegion repaints = layer->repaints(); !repaints.isEmpty()) {
232 *damage += layer->mapToGlobal(repaints);
233 layer->resetRepaints();
234 }
235
236 const QRegion repaints = layer->delegate()->prePaint();
237 if (!repaints.isEmpty()) {
238 *damage += layer->mapToGlobal(repaints);
239 }
240
241 const auto sublayers = layer->sublayers();
242 for (RenderLayer *sublayer : sublayers) {
243 if (sublayer->isVisible()) {
244 prePaintPass(sublayer, damage);
245 }
246 }
247}
248
250{
251 layer->delegate()->postPaint();
252 const auto sublayers = layer->sublayers();
253 for (RenderLayer *sublayer : sublayers) {
254 if (sublayer->isVisible()) {
255 postPaintPass(sublayer);
256 }
257 }
258}
259
260void Compositor::paintPass(RenderLayer *layer, const RenderTarget &renderTarget, const QRegion &region)
261{
262 layer->delegate()->paint(renderTarget, region);
263
264 const auto sublayers = layer->sublayers();
265 for (RenderLayer *sublayer : sublayers) {
266 if (sublayer->isVisible()) {
267 paintPass(sublayer, renderTarget, region);
268 }
269 }
270}
271
273{
274 return m_state == State::On;
275}
276
278{
279 return true;
280}
281
283{
284 return QString();
285}
286
288{
289 return false;
290}
291
293{
294}
295
297{
298}
299
300} // namespace KWin
301
302#include "moc_compositor.cpp"
static Compositor * s_compositor
Definition compositor.h:128
std::unique_ptr< RenderBackend > m_backend
Definition compositor.h:154
virtual bool openGLCompositingIsBroken() const
void postPaintPass(RenderLayer *layer)
QTimer m_unusedSupportPropertyTimer
Definition compositor.h:151
void removeSuperLayer(RenderLayer *layer)
virtual void stop()=0
virtual void composite(RenderLoop *renderLoop)
QList< xcb_atom_t > m_unusedSupportProperties
Definition compositor.h:150
virtual void start()=0
virtual void reinitialize()
void deleteUnusedSupportProperties()
void framePass(RenderLayer *layer, OutputFrame *frame)
virtual bool compositingPossible() const
QHash< RenderLoop *, RenderLayer * > m_superlayers
Definition compositor.h:155
Compositor(QObject *parent=nullptr)
virtual void inhibit(Window *window)
void paintPass(RenderLayer *layer, const RenderTarget &renderTarget, const QRegion &region)
virtual void uninhibit(Window *window)
void prePaintPass(RenderLayer *layer, QRegion *damage)
Output * findOutput(RenderLoop *loop) const
~Compositor() override
void keepSupportProperty(xcb_atom_t atom)
virtual QString compositingNotPossibleReason() const
void addSuperLayer(RenderLayer *layer)
void removeSupportProperty(xcb_atom_t atom)
static Compositor * self()
Replacement for QCursor.
Definition cursor.h:102
QRectF geometry() const
Definition cursor.cpp:190
void markAsRendered(std::chrono::milliseconds timestamp)
Definition cursor.cpp:220
static Cursors * self()
Definition cursor.cpp:35
Cursor * currentCursor() const
Definition cursor.h:285
PresentationModeHint presentationHint() const
Definition item.cpp:455
bool allowTearing
Definition options.h:200
VrrPolicy vrrPolicy() const
Definition output.cpp:657
bool directScanoutInhibited() const
Definition output.cpp:414
virtual RenderLoop * renderLoop() const =0
QRect geometry
Definition output.h:134
QString name
Definition output.h:136
Capabilities capabilities() const
Definition output.cpp:450
virtual bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)=0
QRegion repaints() const
bool needsRepaint() const
virtual std::optional< OutputLayerBeginFrameInfo > beginFrame()=0
virtual bool scanout(SurfaceItem *surfaceItem)
virtual void paint(const RenderTarget &renderTarget, const QRegion &region)=0
virtual SurfaceItem * scanoutCandidate() const
virtual void frame(OutputFrame *frame)
void setOutputLayer(OutputLayer *layer)
RenderLoop * loop() const
QRegion repaints() const
QList< RenderLayer * > sublayers() const
QRectF rect() const
QPoint mapToGlobal(const QPoint &point) const
RenderLayerDelegate * delegate() const
bool needsRepaint() const
void frameRequested(RenderLoop *loop)
std::chrono::nanoseconds lastPresentationTimestamp() const
virtual ContentType contentType() const
SurfaceItem * surfaceItem() const
Definition window.cpp:289
virtual bool isFullScreen() const
Definition window.cpp:3935
bool wantsAdaptiveSync() const
Definition window.cpp:3957
Window * activeWindow() const
Definition workspace.h:767
QList< Output * > outputs() const
Definition workspace.h:762
#define fTraceDuration(...)
Definition ftrace.h:106
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
Options * options
Definition main.cpp:73