KWin
Loading...
Searching...
No Matches
glxcontext.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: 2023 Xaver Hugl <xaver.hugl@gmail.com>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "glxcontext.h"
12
13#include <QDebug>
14#include <QOpenGLContext>
15
16namespace KWin
17{
18
19GlxContext::GlxContext(::Display *display, GLXWindow window, GLXContext handle)
20 : m_display(display)
21 , m_window(window)
22 , m_handle(handle)
23{
24 // It is not legal to not have a vertex array object bound in a core context
25 // to make code handling old and new OpenGL versions easier, bind a dummy vao that's used for everything
26 if (!isOpenglES() && hasOpenglExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) {
27 glGenVertexArrays(1, &m_vao);
28 glBindVertexArray(m_vao);
29 }
30}
31
33{
34 if (m_vao) {
36 glDeleteVertexArrays(1, &m_vao);
37 }
38 glXDestroyContext(m_display, m_handle);
39}
40
42{
43 if (QOpenGLContext *context = QOpenGLContext::currentContext()) {
44 // Workaround to tell Qt that no QOpenGLContext is current
45 context->doneCurrent();
46 }
47 return glXMakeCurrent(m_display, m_window, m_handle);
48}
49
51{
52 return glXMakeCurrent(m_display, None, nullptr);
53}
54
55std::unique_ptr<GlxContext> GlxContext::create(GlxBackend *backend, GLXFBConfig fbconfig, GLXWindow glxWindow)
56{
57 QOpenGLContext *qtGlobalShareContext = QOpenGLContext::globalShareContext();
58 GLXContext globalShareContext = nullptr;
59 if (qtGlobalShareContext) {
60 qDebug(KWIN_X11STANDALONE) << "Global share context format:" << qtGlobalShareContext->format();
61 const auto nativeHandle = qtGlobalShareContext->nativeInterface<QNativeInterface::QGLXContext>();
62 if (nativeHandle) {
63 globalShareContext = nativeHandle->nativeContext();
64 } else {
65 qCDebug(KWIN_X11STANDALONE) << "Invalid QOpenGLContext::globalShareContext()";
66 return nullptr;
67 }
68 }
69 if (!globalShareContext) {
70 qCWarning(KWIN_X11STANDALONE) << "QOpenGLContext::globalShareContext() is required";
71 return nullptr;
72 }
73
74 GLXContext handle = nullptr;
75
76 // Use glXCreateContextAttribsARB() when it's available
77 if (backend->hasExtension(QByteArrayLiteral("GLX_ARB_create_context"))) {
78 const bool have_robustness = backend->hasExtension(QByteArrayLiteral("GLX_ARB_create_context_robustness"));
79 const bool haveVideoMemoryPurge = backend->hasExtension(QByteArrayLiteral("GLX_NV_robustness_video_memory_purge"));
80
81 std::vector<GlxContextAttributeBuilder> candidates;
82 // core
83 if (have_robustness) {
84 if (haveVideoMemoryPurge) {
85 GlxContextAttributeBuilder purgeMemoryCore;
86 purgeMemoryCore.setVersion(3, 1);
87 purgeMemoryCore.setRobust(true);
88 purgeMemoryCore.setResetOnVideoMemoryPurge(true);
89 candidates.emplace_back(std::move(purgeMemoryCore));
90 }
92 robustCore.setVersion(3, 1);
93 robustCore.setRobust(true);
94 candidates.emplace_back(std::move(robustCore));
95 }
97 core.setVersion(3, 1);
98 candidates.emplace_back(std::move(core));
99 // legacy
100 if (have_robustness) {
101 if (haveVideoMemoryPurge) {
102 GlxContextAttributeBuilder purgeMemoryLegacy;
103 purgeMemoryLegacy.setRobust(true);
104 purgeMemoryLegacy.setResetOnVideoMemoryPurge(true);
105 candidates.emplace_back(std::move(purgeMemoryLegacy));
106 }
107 GlxContextAttributeBuilder robustLegacy;
108 robustLegacy.setRobust(true);
109 candidates.emplace_back(std::move(robustLegacy));
110 }
112 legacy.setVersion(2, 1);
113 candidates.emplace_back(std::move(legacy));
114 for (auto it = candidates.begin(); it != candidates.end(); it++) {
115 const auto attribs = it->build();
116 handle = glXCreateContextAttribsARB(backend->display(), fbconfig, globalShareContext, true, attribs.data());
117 if (handle) {
118 qCDebug(KWIN_X11STANDALONE) << "Created GLX context with attributes:" << &(*it);
119 break;
120 }
121 }
122 }
123 if (!handle) {
124 handle = glXCreateNewContext(backend->display(), fbconfig, GLX_RGBA_TYPE, globalShareContext, true);
125 }
126 if (!handle) {
127 qCDebug(KWIN_X11STANDALONE) << "Failed to create an OpenGL context.";
128 return nullptr;
129 }
130 // KWin doesn't support indirect rendering
131 if (!glXIsDirect(backend->display(), handle)) {
132 return nullptr;
133 }
134 if (!glXMakeCurrent(backend->display(), glxWindow, handle)) {
135 glXDestroyContext(backend->display(), handle);
136 return nullptr;
137 }
138 auto ret = std::make_unique<GlxContext>(backend->display(), glxWindow, handle);
139 if (!ret->checkSupported()) {
140 return nullptr;
141 }
142 return ret;
143}
144
145}
OpenGL Backend using GLX over an X overlay window.
::Display * display() const
static std::unique_ptr< GlxContext > create(GlxBackend *backend, GLXFBConfig fbconfig, GLXWindow glxWindow)
GlxContext(::Display *display, GLXWindow window, GLXContext handle)
bool makeCurrent() const
~GlxContext() override
bool doneCurrent() const
bool hasExtension(const QByteArray &extension) const
bool isOpenglES() const
bool hasOpenglExtension(QByteArrayView name) const
@ None
Definition options.h:37
struct _XDisplay Display