File indexing completed on 2024-11-10 04:56:36
0001 /* 0002 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "x11_standalone_omlsynccontrolvsyncmonitor.h" 0008 #include "x11_standalone_glxconvenience.h" 0009 #include "x11_standalone_logging.h" 0010 0011 #include <private/qtx11extras_p.h> 0012 0013 namespace KWin 0014 { 0015 0016 std::unique_ptr<OMLSyncControlVsyncMonitor> OMLSyncControlVsyncMonitor::create() 0017 { 0018 const char *extensions = glXQueryExtensionsString(QX11Info::display(), 0019 QX11Info::appScreen()); 0020 if (!strstr(extensions, "GLX_OML_sync_control")) { 0021 return nullptr; // GLX_OML_sync_control is unsupported. 0022 } 0023 0024 std::unique_ptr<OMLSyncControlVsyncMonitor> monitor{new OMLSyncControlVsyncMonitor()}; 0025 if (monitor->isValid()) { 0026 return monitor; 0027 } else { 0028 return nullptr; 0029 } 0030 } 0031 0032 OMLSyncControlVsyncMonitorHelper::OMLSyncControlVsyncMonitorHelper() 0033 { 0034 // Establish a new X11 connection to avoid locking up the main X11 connection. 0035 m_display = XOpenDisplay(DisplayString(QX11Info::display())); 0036 if (!m_display) { 0037 qCDebug(KWIN_X11STANDALONE) << "Failed to establish vsync monitor X11 connection"; 0038 return; 0039 } 0040 0041 ::Window rootWindow = DefaultRootWindow(m_display); 0042 0043 const int attribs[] = { 0044 GLX_RENDER_TYPE, GLX_RGBA_BIT, 0045 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0046 0}; 0047 0048 GLXFBConfig config = chooseGlxFbConfig(m_display, attribs); 0049 if (!config) { 0050 qCDebug(KWIN_X11STANDALONE) << "Couldn't find any suitable FBConfig for vsync monitor"; 0051 return; 0052 } 0053 0054 XVisualInfo *visualInfo = glXGetVisualFromFBConfig(m_display, config); 0055 if (!visualInfo) { 0056 return; 0057 } 0058 0059 Visual *visual = visualInfo->visual; 0060 const int depth = visualInfo->depth; 0061 XFree(visualInfo); 0062 0063 Colormap colormap = XCreateColormap(m_display, rootWindow, visual, AllocNone); 0064 XSetWindowAttributes attributes; 0065 attributes.colormap = colormap; 0066 0067 m_dummyWindow = XCreateWindow(m_display, rootWindow, 0, 0, 1, 1, 0, depth, 0068 InputOutput, visual, CWColormap, &attributes); 0069 XFreeColormap(m_display, colormap); 0070 if (!m_dummyWindow) { 0071 qCDebug(KWIN_X11STANDALONE) << "Failed to create a dummy window for vsync monitor"; 0072 return; 0073 } 0074 0075 m_drawable = glXCreateWindow(m_display, config, m_dummyWindow, nullptr); 0076 if (!m_drawable) { 0077 qCDebug(KWIN_X11STANDALONE) << "Failed to create GLXWindow for dummy window"; 0078 return; 0079 } 0080 0081 m_localContext = glXCreateNewContext(m_display, config, GLX_RGBA_TYPE, 0, true); 0082 if (!m_localContext) { 0083 qCDebug(KWIN_X11STANDALONE) << "Failed to create opengl context for vsync monitor"; 0084 return; 0085 } 0086 } 0087 0088 OMLSyncControlVsyncMonitorHelper::~OMLSyncControlVsyncMonitorHelper() 0089 { 0090 if (m_localContext) { 0091 glXDestroyContext(m_display, m_localContext); 0092 } 0093 if (m_drawable) { 0094 glXDestroyWindow(m_display, m_drawable); 0095 } 0096 if (m_dummyWindow) { 0097 XDestroyWindow(m_display, m_dummyWindow); 0098 } 0099 if (m_display) { 0100 XCloseDisplay(m_display); 0101 } 0102 } 0103 0104 bool OMLSyncControlVsyncMonitorHelper::isValid() const 0105 { 0106 return m_display && m_localContext && m_drawable; 0107 } 0108 0109 void OMLSyncControlVsyncMonitorHelper::poll() 0110 { 0111 if (!glXMakeCurrent(m_display, m_drawable, m_localContext)) { 0112 qCDebug(KWIN_X11STANDALONE) << "Failed to make vsync monitor OpenGL context current"; 0113 return; 0114 } 0115 0116 int64_t ust, msc, sbc; 0117 0118 glXGetSyncValuesOML(m_display, m_drawable, &ust, &msc, &sbc); 0119 glXWaitForMscOML(m_display, m_drawable, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc); 0120 0121 Q_EMIT vblankOccurred(std::chrono::microseconds(ust)); 0122 } 0123 0124 OMLSyncControlVsyncMonitor::OMLSyncControlVsyncMonitor() 0125 { 0126 m_helper.moveToThread(&m_thread); 0127 0128 connect(&m_helper, &OMLSyncControlVsyncMonitorHelper::errorOccurred, 0129 this, &OMLSyncControlVsyncMonitor::errorOccurred); 0130 connect(&m_helper, &OMLSyncControlVsyncMonitorHelper::vblankOccurred, 0131 this, &OMLSyncControlVsyncMonitor::vblankOccurred); 0132 0133 m_thread.setObjectName(QStringLiteral("vsync event monitor")); 0134 m_thread.start(); 0135 } 0136 0137 OMLSyncControlVsyncMonitor::~OMLSyncControlVsyncMonitor() 0138 { 0139 m_thread.quit(); 0140 m_thread.wait(); 0141 } 0142 0143 bool OMLSyncControlVsyncMonitor::isValid() const 0144 { 0145 return m_helper.isValid(); 0146 } 0147 0148 void OMLSyncControlVsyncMonitor::arm() 0149 { 0150 QMetaObject::invokeMethod(&m_helper, &OMLSyncControlVsyncMonitorHelper::poll); 0151 } 0152 0153 } // namespace KWin 0154 0155 #include "moc_x11_standalone_omlsynccontrolvsyncmonitor.cpp"