KWin
Loading...
Searching...
No Matches
x11syncmanager.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2014 Fredrik Höglund <fredrik@kde.org>
3
4 Explicit command stream synchronization based on the sample implementation by James Jones <jajones@nvidia.com>,
5 SPDX-FileCopyrightText: 2011 NVIDIA Corporation
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "x11syncmanager.h"
10#include "compositor.h"
11#include "core/outputbackend.h"
12#include "core/renderbackend.h"
13#include "main.h"
15#include "utils/common.h"
16
17#include "opengl/glplatform.h"
18
19namespace KWin
20{
21
23{
24 m_state = Ready;
25
26 xcb_connection_t *const connection = kwinApp()->x11Connection();
27 m_fence = xcb_generate_id(connection);
28 xcb_sync_create_fence(connection, kwinApp()->x11RootWindow(), m_fence, false);
29 xcb_flush(connection);
30
31 m_sync = glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, m_fence, 0);
32}
33
35{
36 xcb_connection_t *const connection = kwinApp()->x11Connection();
37 // If glDeleteSync is called before the xcb fence is signalled
38 // the nvidia driver (the only one to implement GL_SYNC_X11_FENCE_EXT)
39 // deadlocks waiting for the fence to be signalled.
40 // To avoid this, make sure the fence is signalled before
41 // deleting the sync.
42 if (m_state == Resetting || m_state == Ready) {
43 trigger();
44 // The flush is necessary!
45 // The trigger command needs to be sent to the X server.
46 xcb_flush(connection);
47 }
48 xcb_sync_destroy_fence(connection, m_fence);
49 glDeleteSync(m_sync);
50
51 if (m_state == Resetting) {
52 xcb_discard_reply(connection, m_reset_cookie.sequence);
53 }
54}
55
57{
58 Q_ASSERT(m_state == Ready || m_state == Resetting);
59
60 // Finish resetting the fence if necessary
61 if (m_state == Resetting) {
63 }
64
65 xcb_sync_trigger_fence(kwinApp()->x11Connection(), m_fence);
66 m_state = TriggerSent;
67}
68
70{
71 if (m_state != TriggerSent) {
72 return;
73 }
74
75 glWaitSync(m_sync, 0, GL_TIMEOUT_IGNORED);
76 m_state = Waiting;
77}
78
80{
81 if (m_state == Done) {
82 return true;
83 }
84
85 // Note: It is possible that we never inserted a wait for the fence.
86 // This can happen if we ended up not rendering the damaged
87 // window because it is fully occluded.
88 Q_ASSERT(m_state == TriggerSent || m_state == Waiting);
89
90 // Check if the fence is signaled
91 GLint value;
92 glGetSynciv(m_sync, GL_SYNC_STATUS, 1, nullptr, &value);
93
94 if (value != GL_SIGNALED) {
95 qCDebug(KWIN_CORE) << "Waiting for X fence to finish";
96
97 // Wait for the fence to become signaled with a one second timeout
98 const GLenum result = glClientWaitSync(m_sync, 0, 1000000000);
99
100 switch (result) {
101 case GL_TIMEOUT_EXPIRED:
102 qCWarning(KWIN_CORE) << "Timeout while waiting for X fence";
103 return false;
104
105 case GL_WAIT_FAILED:
106 qCWarning(KWIN_CORE) << "glClientWaitSync() failed";
107 return false;
108 }
109 }
110
111 m_state = Done;
112 return true;
113}
114
116{
117 Q_ASSERT(m_state == Done);
118
119 xcb_connection_t *const connection = kwinApp()->x11Connection();
120
121 // Send the reset request along with a sync request.
122 // We use the cookie to ensure that the server has processed the reset
123 // request before we trigger the fence and call glWaitSync().
124 // Otherwise there is a race condition between the reset finishing and
125 // the glWaitSync() call.
126 xcb_sync_reset_fence(connection, m_fence);
127 m_reset_cookie = xcb_get_input_focus(connection);
128 xcb_flush(connection);
129
130 m_state = Resetting;
131}
132
134{
135 Q_ASSERT(m_state == Resetting);
136 free(xcb_get_input_focus_reply(kwinApp()->x11Connection(), m_reset_cookie, nullptr));
137 m_state = Ready;
138}
139
141{
142 if (kwinApp()->operationMode() != Application::OperationModeX11) {
143 return nullptr;
144 }
145
146 if (Compositor::self()->backend()->compositingType() != OpenGLCompositing) {
147 return nullptr;
148 }
149
150 GLPlatform *glPlatform = GLPlatform::instance();
151 const bool haveSyncObjects = glPlatform->isGLES()
152 ? hasGLVersion(3, 0)
153 : hasGLVersion(3, 2) || hasGLExtension("GL_ARB_sync");
154
155 if (hasGLExtension("GL_EXT_x11_sync_object") && haveSyncObjects) {
156 const QString useExplicitSync = qEnvironmentVariable("KWIN_EXPLICIT_SYNC");
157
158 if (useExplicitSync != QLatin1String("0")) {
159 qCDebug(KWIN_CORE) << "Initializing fences for synchronization with the X command stream";
160 return new X11SyncManager;
161 } else {
162 qCDebug(KWIN_CORE) << "Explicit synchronization with the X command stream disabled by environment variable";
163 }
164 }
165 return nullptr;
166}
167
168X11SyncManager::X11SyncManager()
169{
170 for (int i = 0; i < MaxFences; ++i) {
171 m_fences.append(new X11SyncObject);
172 }
173}
174
176{
178 qDeleteAll(m_fences);
179}
180
182{
183 if (!m_currentFence) {
184 return true;
185 }
186
187 for (int i = 0; i < std::min<int>(2, m_fences.count() - 1); i++) {
188 const int index = (m_next + i) % m_fences.count();
189 X11SyncObject *fence = m_fences[index];
190
191 switch (fence->state()) {
193 break;
194
197 if (!fence->finish()) {
198 return false;
199 }
200 fence->reset();
201 break;
202
203 // Should not happen in practice since we always reset the fence after finishing it
205 fence->reset();
206 break;
207
209 fence->finishResetting();
210 break;
211 }
212 }
213
214 m_currentFence = nullptr;
215 return true;
216}
217
219{
220 m_currentFence = m_fences[m_next];
221 m_next = (m_next + 1) % m_fences.count();
222 m_currentFence->trigger();
223}
224
226{
227 if (m_currentFence && m_currentFence->state() != X11SyncObject::Waiting) {
228 m_currentFence->wait();
229 }
230}
231
232} // namespace KWin
@ OperationModeX11
KWin uses only X11 for managing windows and compositing.
Definition main.h:87
WorkspaceScene * scene() const
Definition compositor.h:60
static Compositor * self()
static GLPlatform * instance()
Definition glplatform.h:394
bool isGLES() const
virtual bool makeOpenGLContextCurrent()
static X11SyncManager * create()
State state() const
bool hasGLVersion(int major, int minor, int release)
Definition glutils.cpp:133
@ OpenGLCompositing
Definition globals.h:37
bool hasGLExtension(const QByteArray &extension)
Definition glutils.cpp:138
KWIN_EXPORT xcb_connection_t * connection()
Definition xcb.h:19