KWin
Loading...
Searching...
No Matches
x11_standalone_sgivideosyncvsyncmonitor.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
10
11#include <private/qtx11extras_p.h>
12
13namespace KWin
14{
15
16std::unique_ptr<SGIVideoSyncVsyncMonitor> SGIVideoSyncVsyncMonitor::create()
17{
18 const char *extensions = glXQueryExtensionsString(QX11Info::display(),
19 QX11Info::appScreen());
20 if (!strstr(extensions, "GLX_SGI_video_sync")) {
21 return nullptr; // GLX_SGI_video_sync is unsupported.
22 }
23
24 std::unique_ptr<SGIVideoSyncVsyncMonitor> monitor{new SGIVideoSyncVsyncMonitor()};
25 if (monitor->isValid()) {
26 return monitor;
27 } else {
28 return nullptr;
29 }
30}
31
33{
34 // Establish a new X11 connection to avoid locking up the main X11 connection.
35 m_display = XOpenDisplay(DisplayString(QX11Info::display()));
36 if (!m_display) {
37 qCDebug(KWIN_X11STANDALONE) << "Failed to establish vsync monitor X11 connection";
38 return;
39 }
40
41 ::Window rootWindow = DefaultRootWindow(m_display);
42
43 const int attribs[] = {
44 GLX_RENDER_TYPE, GLX_RGBA_BIT,
45 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
46 0};
47
48 GLXFBConfig config = chooseGlxFbConfig(m_display, attribs);
49 if (!config) {
50 qCDebug(KWIN_X11STANDALONE) << "Couldn't find any suitable FBConfig for vsync monitor";
51 return;
52 }
53
54 XVisualInfo *visualInfo = glXGetVisualFromFBConfig(m_display, config);
55 if (!visualInfo) {
56 return;
57 }
58
59 Visual *visual = visualInfo->visual;
60 const int depth = visualInfo->depth;
61 XFree(visualInfo);
62
63 Colormap colormap = XCreateColormap(m_display, rootWindow, visual, AllocNone);
64 XSetWindowAttributes attributes;
65 attributes.colormap = colormap;
66
67 m_dummyWindow = XCreateWindow(m_display, rootWindow, 0, 0, 1, 1, 0, depth,
68 InputOutput, visual, CWColormap, &attributes);
69 XFreeColormap(m_display, colormap);
70 if (!m_dummyWindow) {
71 qCDebug(KWIN_X11STANDALONE) << "Failed to create a dummy window for vsync monitor";
72 return;
73 }
74
75 m_drawable = glXCreateWindow(m_display, config, m_dummyWindow, nullptr);
76 if (!m_drawable) {
77 qCDebug(KWIN_X11STANDALONE) << "Failed to create GLXWindow for dummy window";
78 return;
79 }
80
81 m_localContext = glXCreateNewContext(m_display, config, GLX_RGBA_TYPE, 0, true);
82 if (!m_localContext) {
83 qCDebug(KWIN_X11STANDALONE) << "Failed to create opengl context for vsync monitor";
84 return;
85 }
86}
87
89{
90 if (m_localContext) {
91 glXDestroyContext(m_display, m_localContext);
92 }
93 if (m_drawable) {
94 glXDestroyWindow(m_display, m_drawable);
95 }
96 if (m_dummyWindow) {
97 XDestroyWindow(m_display, m_dummyWindow);
98 }
99 if (m_display) {
100 XCloseDisplay(m_display);
101 }
102}
103
105{
106 return m_display && m_localContext && m_drawable;
107}
108
110{
111 if (!glXMakeCurrent(m_display, m_drawable, m_localContext)) {
112 qCDebug(KWIN_X11STANDALONE) << "Failed to make vsync monitor OpenGL context current";
113 Q_EMIT errorOccurred();
114 return;
115 }
116
117 uint count;
118
119 glXGetVideoSyncSGI(&count);
120 glXWaitVideoSyncSGI(2, (count + 1) % 2, &count);
121
122 // Using monotonic clock is inaccurate, but it's still a pretty good estimate.
123 Q_EMIT vblankOccurred(std::chrono::steady_clock::now().time_since_epoch());
124}
125
126SGIVideoSyncVsyncMonitor::SGIVideoSyncVsyncMonitor()
127{
128 m_helper.moveToThread(&m_thread);
129
134
135 m_thread.setObjectName(QStringLiteral("vsync event monitor"));
136 m_thread.start();
137}
138
140{
141 m_thread.quit();
142 m_thread.wait();
143}
144
146{
147 return m_helper.isValid();
148}
149
151{
152 QMetaObject::invokeMethod(&m_helper, &SGIVideoSyncVsyncMonitorHelper::poll);
153}
154
155} // namespace KWin
156
157#include "moc_x11_standalone_sgivideosyncvsyncmonitor.cpp"
void vblankOccurred(std::chrono::nanoseconds timestamp)
static std::unique_ptr< SGIVideoSyncVsyncMonitor > create()
void vblankOccurred(std::chrono::nanoseconds timestamp)
KWIN_EXPORT xcb_window_t rootWindow()
Definition xcb.h:24
GLXFBConfig chooseGlxFbConfig(::Display *display, const int attributes[])