KWin
Loading...
Searching...
No Matches
glutils.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: 2006-2007 Rivo Laks <rivolaks@hot.ee>
6 SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
7 SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@kde.org>
8
9 SPDX-License-Identifier: GPL-2.0-or-later
10*/
11
12#include "opengl/glutils.h"
13#include "glplatform.h"
14#include "gltexture_p.h"
15#include "utils/common.h"
16
17namespace KWin
18{
19
20static QList<QByteArray> glExtensions;
21
22// Functions
23
24static void initDebugOutput()
25{
26 const bool have_KHR_debug = hasGLExtension(QByteArrayLiteral("GL_KHR_debug"));
27 const bool have_ARB_debug = hasGLExtension(QByteArrayLiteral("GL_ARB_debug_output"));
28 if (!have_KHR_debug && !have_ARB_debug) {
29 return;
30 }
31
32 if (!have_ARB_debug) {
33 // if we don't have ARB debug, but only KHR debug we need to verify whether the context is a debug context
34 // it should work without as well, but empirical tests show: no it doesn't
35 if (GLPlatform::instance()->isGLES()) {
36 if (!hasGLVersion(3, 2)) {
37 // empirical data shows extension doesn't work
38 return;
39 }
40 } else if (!hasGLVersion(3, 0)) {
41 return;
42 }
43 // can only be queried with either OpenGL >= 3.0 or OpenGL ES of at least 3.1
44 GLint value = 0;
45 glGetIntegerv(GL_CONTEXT_FLAGS, &value);
46 if (!(value & GL_CONTEXT_FLAG_DEBUG_BIT)) {
47 return;
48 }
49 }
50
51 // Set the callback function
52 auto callback = [](GLenum source, GLenum type, GLuint id,
53 GLenum severity, GLsizei length,
54 const GLchar *message,
55 const GLvoid *userParam) {
56 while (length && std::isspace(message[length - 1])) {
57 --length;
58 }
59
60 switch (type) {
61 case GL_DEBUG_TYPE_ERROR:
62 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
63 qCWarning(KWIN_OPENGL, "%#x: %.*s", id, length, message);
64 break;
65
66 case GL_DEBUG_TYPE_OTHER:
67 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
68 case GL_DEBUG_TYPE_PORTABILITY:
69 case GL_DEBUG_TYPE_PERFORMANCE:
70 default:
71 qCDebug(KWIN_OPENGL, "%#x: %.*s", id, length, message);
72 break;
73 }
74 };
75
76 glDebugMessageCallback(callback, nullptr);
77
78 // This state exists only in GL_KHR_debug
79 if (have_KHR_debug) {
80 glEnable(GL_DEBUG_OUTPUT);
81 }
82
83 if (qEnvironmentVariableIntValue("KWIN_GL_DEBUG")) {
84 // Enable all debug messages
85 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
86 // Insert a test message
87 const QByteArray message = QByteArrayLiteral("OpenGL debug output initialized");
88 glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 0,
89 GL_DEBUG_SEVERITY_LOW, message.length(), message.constData());
90 } else {
91 // Only enable error messages
92 glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, nullptr, GL_TRUE);
93 glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, GL_DONT_CARE, 0, nullptr, GL_TRUE);
94 }
95}
96
97void initGL(const std::function<resolveFuncPtr(const char *)> &resolveFunction)
98{
99 // Get list of supported OpenGL extensions
100 if (hasGLVersion(3, 0)) {
101 int count;
102 glGetIntegerv(GL_NUM_EXTENSIONS, &count);
103
104 for (int i = 0; i < count; i++) {
105 const QByteArray name = (const char *)glGetStringi(GL_EXTENSIONS, i);
106 glExtensions << name;
107 }
108 } else {
109 glExtensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' ');
110 }
111
112 // handle OpenGL extensions functions
113 glResolveFunctions(resolveFunction);
114
115 initDebugOutput();
116
120}
121
123{
125 GLTexturePrivate::cleanup();
126 GLFramebuffer::cleanup();
128 GLPlatform::cleanup();
129
130 glExtensions.clear();
131}
132
133bool hasGLVersion(int major, int minor, int release)
134{
135 return GLPlatform::instance()->glVersion() >= Version(major, minor, release);
136}
137
138bool hasGLExtension(const QByteArray &extension)
139{
140 return glExtensions.contains(extension);
141}
142
143QList<QByteArray> openGLExtensions()
144{
145 return glExtensions;
146}
147
148static QString formatGLError(GLenum err)
149{
150 switch (err) {
151 case GL_NO_ERROR:
152 return QStringLiteral("GL_NO_ERROR");
153 case GL_INVALID_ENUM:
154 return QStringLiteral("GL_INVALID_ENUM");
155 case GL_INVALID_VALUE:
156 return QStringLiteral("GL_INVALID_VALUE");
157 case GL_INVALID_OPERATION:
158 return QStringLiteral("GL_INVALID_OPERATION");
159 case GL_STACK_OVERFLOW:
160 return QStringLiteral("GL_STACK_OVERFLOW");
161 case GL_STACK_UNDERFLOW:
162 return QStringLiteral("GL_STACK_UNDERFLOW");
163 case GL_OUT_OF_MEMORY:
164 return QStringLiteral("GL_OUT_OF_MEMORY");
165 default:
166 return QLatin1String("0x") + QString::number(err, 16);
167 }
168}
169
170bool checkGLError(const char *txt)
171{
172 GLenum err = glGetError();
173 if (err == GL_CONTEXT_LOST) {
174 qCWarning(KWIN_OPENGL) << "GL error: context lost";
175 return true;
176 }
177 bool hasError = false;
178 while (err != GL_NO_ERROR) {
179 qCWarning(KWIN_OPENGL) << "GL error (" << txt << "): " << formatGLError(err);
180 hasError = true;
181 err = glGetError();
182 if (err == GL_CONTEXT_LOST) {
183 qCWarning(KWIN_OPENGL) << "GL error: context lost";
184 break;
185 }
186 }
187 return hasError;
188}
189
190} // namespace
static void initStatic()
static GLPlatform * instance()
Definition glplatform.h:394
Version glVersion() const
static void initStatic()
bool checkGLError(const char *txt)
Definition glutils.cpp:170
Session::Type type
Definition session.cpp:17
void(* resolveFuncPtr)()
Definition glutils.h:31
void KWIN_EXPORT cleanupGL()
Definition glutils.cpp:122
void initGL(const std::function< resolveFuncPtr(const char *)> &resolveFunction)
Definition glutils.cpp:97
QList< QByteArray > openGLExtensions()
Definition glutils.cpp:143
bool hasGLVersion(int major, int minor, int release)
Definition glutils.cpp:133
bool hasGLExtension(const QByteArray &extension)
Definition glutils.cpp:138
void glResolveFunctions(const std::function< resolveFuncPtr(const char *)> &resolveFunction)