File indexing completed on 2024-11-10 04:56:34
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@gmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "glxcontext.h" 0010 #include "x11_standalone_glx_context_attribute_builder.h" 0011 #include "x11_standalone_logging.h" 0012 0013 #include <QDebug> 0014 #include <QOpenGLContext> 0015 0016 namespace KWin 0017 { 0018 0019 GlxContext::GlxContext(::Display *display, GLXWindow window, GLXContext handle) 0020 : m_display(display) 0021 , m_window(window) 0022 , m_handle(handle) 0023 { 0024 // It is not legal to not have a vertex array object bound in a core context 0025 // to make code handling old and new OpenGL versions easier, bind a dummy vao that's used for everything 0026 if (!isOpenglES() && hasOpenglExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) { 0027 glGenVertexArrays(1, &m_vao); 0028 glBindVertexArray(m_vao); 0029 } 0030 } 0031 0032 GlxContext::~GlxContext() 0033 { 0034 if (m_vao) { 0035 makeCurrent(); 0036 glDeleteVertexArrays(1, &m_vao); 0037 } 0038 glXDestroyContext(m_display, m_handle); 0039 } 0040 0041 bool GlxContext::makeCurrent() const 0042 { 0043 if (QOpenGLContext *context = QOpenGLContext::currentContext()) { 0044 // Workaround to tell Qt that no QOpenGLContext is current 0045 context->doneCurrent(); 0046 } 0047 return glXMakeCurrent(m_display, m_window, m_handle); 0048 } 0049 0050 bool GlxContext::doneCurrent() const 0051 { 0052 return glXMakeCurrent(m_display, None, nullptr); 0053 } 0054 0055 std::unique_ptr<GlxContext> GlxContext::create(GlxBackend *backend, GLXFBConfig fbconfig, GLXWindow glxWindow) 0056 { 0057 QOpenGLContext *qtGlobalShareContext = QOpenGLContext::globalShareContext(); 0058 GLXContext globalShareContext = nullptr; 0059 if (qtGlobalShareContext) { 0060 qDebug(KWIN_X11STANDALONE) << "Global share context format:" << qtGlobalShareContext->format(); 0061 const auto nativeHandle = qtGlobalShareContext->nativeInterface<QNativeInterface::QGLXContext>(); 0062 if (nativeHandle) { 0063 globalShareContext = nativeHandle->nativeContext(); 0064 } else { 0065 qCDebug(KWIN_X11STANDALONE) << "Invalid QOpenGLContext::globalShareContext()"; 0066 return nullptr; 0067 } 0068 } 0069 if (!globalShareContext) { 0070 qCWarning(KWIN_X11STANDALONE) << "QOpenGLContext::globalShareContext() is required"; 0071 return nullptr; 0072 } 0073 0074 GLXContext handle = nullptr; 0075 0076 // Use glXCreateContextAttribsARB() when it's available 0077 if (backend->hasExtension(QByteArrayLiteral("GLX_ARB_create_context"))) { 0078 const bool have_robustness = backend->hasExtension(QByteArrayLiteral("GLX_ARB_create_context_robustness")); 0079 const bool haveVideoMemoryPurge = backend->hasExtension(QByteArrayLiteral("GLX_NV_robustness_video_memory_purge")); 0080 0081 std::vector<GlxContextAttributeBuilder> candidates; 0082 // core 0083 if (have_robustness) { 0084 if (haveVideoMemoryPurge) { 0085 GlxContextAttributeBuilder purgeMemoryCore; 0086 purgeMemoryCore.setVersion(3, 1); 0087 purgeMemoryCore.setRobust(true); 0088 purgeMemoryCore.setResetOnVideoMemoryPurge(true); 0089 candidates.emplace_back(std::move(purgeMemoryCore)); 0090 } 0091 GlxContextAttributeBuilder robustCore; 0092 robustCore.setVersion(3, 1); 0093 robustCore.setRobust(true); 0094 candidates.emplace_back(std::move(robustCore)); 0095 } 0096 GlxContextAttributeBuilder core; 0097 core.setVersion(3, 1); 0098 candidates.emplace_back(std::move(core)); 0099 // legacy 0100 if (have_robustness) { 0101 if (haveVideoMemoryPurge) { 0102 GlxContextAttributeBuilder purgeMemoryLegacy; 0103 purgeMemoryLegacy.setRobust(true); 0104 purgeMemoryLegacy.setResetOnVideoMemoryPurge(true); 0105 candidates.emplace_back(std::move(purgeMemoryLegacy)); 0106 } 0107 GlxContextAttributeBuilder robustLegacy; 0108 robustLegacy.setRobust(true); 0109 candidates.emplace_back(std::move(robustLegacy)); 0110 } 0111 GlxContextAttributeBuilder legacy; 0112 legacy.setVersion(2, 1); 0113 candidates.emplace_back(std::move(legacy)); 0114 for (auto it = candidates.begin(); it != candidates.end(); it++) { 0115 const auto attribs = it->build(); 0116 handle = glXCreateContextAttribsARB(backend->display(), fbconfig, globalShareContext, true, attribs.data()); 0117 if (handle) { 0118 qCDebug(KWIN_X11STANDALONE) << "Created GLX context with attributes:" << &(*it); 0119 break; 0120 } 0121 } 0122 } 0123 if (!handle) { 0124 handle = glXCreateNewContext(backend->display(), fbconfig, GLX_RGBA_TYPE, globalShareContext, true); 0125 } 0126 if (!handle) { 0127 qCDebug(KWIN_X11STANDALONE) << "Failed to create an OpenGL context."; 0128 return nullptr; 0129 } 0130 // KWin doesn't support indirect rendering 0131 if (!glXIsDirect(backend->display(), handle)) { 0132 return nullptr; 0133 } 0134 if (!glXMakeCurrent(backend->display(), glxWindow, handle)) { 0135 glXDestroyContext(backend->display(), handle); 0136 return nullptr; 0137 } 0138 auto ret = std::make_unique<GlxContext>(backend->display(), glxWindow, handle); 0139 if (!ret->checkSupported()) { 0140 return nullptr; 0141 } 0142 return ret; 0143 } 0144 0145 }