Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qopenglfunctions.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qopenglfunctions.h"
7#include "qdebug.h"
8#include <QtGui/private/qopenglcontext_p.h>
9#include <QtGui/private/qopengl_p.h>
10#include <QtGui/private/qguiapplication_p.h>
11#include <qpa/qplatformintegration.h>
12#include <qpa/qplatformnativeinterface.h>
13
14#ifdef Q_OS_INTEGRITY
15#include <EGL/egl.h>
16#endif
17
18#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE_EXT
19#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA
20#endif
21
23
24using namespace Qt::StringLiterals;
25
26#define QT_OPENGL_COUNT_FUNCTIONS(ret, name, args) +1
27#define QT_OPENGL_FUNCTION_NAMES(ret, name, args) \
28 "gl"#name"\0"
29#define QT_OPENGL_FLAGS(ret, name, args) \
30 0,
31#define QT_OPENGL_IMPLEMENT(CLASS, FUNCTIONS) \
32void CLASS::init(QOpenGLContext *context) \
33{ \
34 const char *names = FUNCTIONS(QT_OPENGL_FUNCTION_NAMES); \
35 const char *name = names; \
36 for (int i = 0; i < FUNCTIONS(QT_OPENGL_COUNT_FUNCTIONS); ++i) { \
37 functions[i] = QT_PREPEND_NAMESPACE(getProcAddress(context, name)); \
38 name += strlen(name) + 1; \
39 } \
40}
41
124// Hidden private fields for additional extension data.
126{
133
134 void invalidateResource() override
135 {
136 m_features = -1;
137 m_extensions = -1;
138 }
139
141 {
142 // no gl resources to free
143 }
144
147};
148
149Q_GLOBAL_STATIC(QOpenGLMultiGroupSharedResource, qt_gl_functions_resource)
150
152{
153 if (!context)
157 qt_gl_functions_resource()->value<QOpenGLFunctionsPrivateEx>(context);
158 return funcs;
159}
160
172
187 : d_ptr(nullptr)
188{
191 else
192 qWarning("QOpenGLFunctions created with non-current context");
193}
194
198
203
211{
213 QOpenGLExtensionMatcher extensions;
214 int features = 0;
215 if ((extensions.match("GL_KHR_blend_equation_advanced")
216 || extensions.match("GL_NV_blend_equation_advanced")) &&
217 (extensions.match("GL_KHR_blend_equation_advanced_coherent")
218 || extensions.match("GL_NV_blend_equation_advanced_coherent"))) {
219 // We need both the advanced equations and the coherency for us
220 // to be able to easily use the new blend equations
222 }
223 if (ctx->isOpenGLES()) {
224 // OpenGL ES
237 if (extensions.match("GL_IMG_texture_npot"))
239 if (extensions.match("GL_OES_texture_npot"))
242 if (ctx->format().majorVersion() >= 3 || extensions.match("GL_EXT_texture_rg")) {
243 // Mesa's GLES implementation (as of 10.6.0) is unable to handle this, even though it provides 3.0.
244 const char *renderer = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_RENDERER));
245 if (!(renderer && strstr(renderer, "Mesa")))
247 }
248 if (ctx->format().majorVersion() >= 3) {
250 if (ctx->format().minorVersion() >= 2 && extensions.match("GL_KHR_blend_equation_advanced_coherent")) {
251 // GL_KHR_blend_equation_advanced is included in OpenGL ES/3.2
253 }
254 }
255 return features;
256 } else {
257 // OpenGL
260
261 if (format.majorVersion() >= 3)
263 else if (extensions.match("GL_EXT_framebuffer_object") || extensions.match("GL_ARB_framebuffer_object"))
265
266 if (format.majorVersion() >= 2) {
267 features |= QOpenGLFunctions::BlendColor |
280 } else {
281 // Recognize features by extension name.
282 if (extensions.match("GL_ARB_multitexture"))
284 if (extensions.match("GL_ARB_shader_objects"))
285 features |= QOpenGLFunctions::Shaders;
286 if (extensions.match("GL_EXT_blend_color"))
288 if (extensions.match("GL_EXT_blend_equation_separate"))
290 if (extensions.match("GL_EXT_blend_subtract"))
292 if (extensions.match("GL_EXT_blend_func_separate"))
294 if (extensions.match("GL_ARB_texture_compression"))
296 if (extensions.match("GL_ARB_multisample"))
298 if (extensions.match("GL_ARB_texture_non_power_of_two"))
301 }
302
303 const QPair<int, int> version = format.version();
304 if (version < qMakePair(3, 0)
305 || (version == qMakePair(3, 0) && format.testOption(QSurfaceFormat::DeprecatedFunctions))
306 || (version == qMakePair(3, 1) && extensions.match("GL_ARB_compatibility"))
307 || (version >= qMakePair(3, 2) && format.profile() == QSurfaceFormat::CompatibilityProfile)) {
309 }
310 return features;
311 }
312}
313
315{
316 int extensions = 0;
317 QOpenGLExtensionMatcher extensionMatcher;
319 QSurfaceFormat format = ctx->format();
320
321 if (extensionMatcher.match("GL_EXT_bgra"))
323 if (extensionMatcher.match("GL_ARB_texture_rectangle"))
325 if (extensionMatcher.match("GL_ARB_texture_compression"))
327 if (extensionMatcher.match("GL_EXT_texture_compression_s3tc"))
329 if (extensionMatcher.match("GL_OES_compressed_ETC1_RGB8_texture"))
331 if (extensionMatcher.match("GL_IMG_texture_compression_pvrtc"))
333 if (extensionMatcher.match("GL_KHR_texture_compression_astc_ldr"))
335 if (extensionMatcher.match("GL_ARB_texture_mirrored_repeat"))
337 if (extensionMatcher.match("GL_EXT_stencil_two_side"))
339 if (extensionMatcher.match("GL_EXT_stencil_wrap"))
340 extensions |= QOpenGLExtensions::StencilWrap;
341 if (extensionMatcher.match("GL_NV_float_buffer"))
343 if (extensionMatcher.match("GL_ARB_pixel_buffer_object"))
345 if (extensionMatcher.match("GL_ARB_texture_swizzle") || extensionMatcher.match("GL_EXT_texture_swizzle"))
347 if (extensionMatcher.match("GL_OES_standard_derivatives"))
349 if (extensionMatcher.match("GL_ARB_half_float_vertex"))
351 if (extensionMatcher.match("GL_OVR_multiview"))
352 extensions |= QOpenGLExtensions::MultiView;
353 if (extensionMatcher.match("GL_OVR_multiview2"))
355
356 if (ctx->isOpenGLES()) {
357 if (format.majorVersion() >= 2)
359
360 if (format.majorVersion() >= 3) {
372#ifndef Q_OS_WASM
373 // WebGL 2.0 specification explicitly does not support texture swizzles
374 // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.19
376#endif
377 } else {
378 // Recognize features by extension name.
379 if (extensionMatcher.match("GL_OES_packed_depth_stencil"))
381 if (extensionMatcher.match("GL_OES_depth24"))
382 extensions |= QOpenGLExtensions::Depth24;
383 if (extensionMatcher.match("GL_ANGLE_framebuffer_blit"))
385 if (extensionMatcher.match("GL_ANGLE_framebuffer_multisample"))
387 if (extensionMatcher.match("GL_NV_framebuffer_blit"))
389 if (extensionMatcher.match("GL_NV_framebuffer_multisample"))
391 if (extensionMatcher.match("GL_OES_rgb8_rgba8"))
393 if (extensionMatcher.match("GL_OES_compressed_ETC2_RGB8_texture"))
395 }
396
397 if (extensionMatcher.match("GL_OES_mapbuffer"))
398 extensions |= QOpenGLExtensions::MapBuffer;
399 if (extensionMatcher.match("GL_OES_element_index_uint"))
401 // We don't match GL_APPLE_texture_format_BGRA8888 here because it has different semantics.
402 if (extensionMatcher.match("GL_IMG_texture_format_BGRA8888") || extensionMatcher.match("GL_EXT_texture_format_BGRA8888"))
404#ifdef Q_OS_ANDROID
405 QString *deviceName =
406 static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName"));
407 static bool wrongfullyReportsBgra8888Support = deviceName != 0
408 && (deviceName->compare("samsung SM-T211"_L1, Qt::CaseInsensitive) == 0
409 || deviceName->compare("samsung SM-T210"_L1, Qt::CaseInsensitive) == 0
410 || deviceName->compare("samsung SM-T215"_L1, Qt::CaseInsensitive) == 0);
411 if (wrongfullyReportsBgra8888Support)
412 extensions &= ~QOpenGLExtensions::BGRATextureFormat;
413#endif
414
415 if (extensionMatcher.match("GL_EXT_discard_framebuffer"))
417 if (extensionMatcher.match("GL_EXT_texture_norm16"))
419 } else {
423
424 if (format.version() >= qMakePair(1, 2))
426
427 if (format.version() >= qMakePair(1, 4) || extensionMatcher.match("GL_SGIS_generate_mipmap"))
429
430 if (format.majorVersion() >= 2)
432
433 if (format.majorVersion() >= 3 || extensionMatcher.match("GL_ARB_framebuffer_object")) {
438 } else {
439 // Recognize features by extension name.
440 if (extensionMatcher.match("GL_EXT_framebuffer_multisample"))
442 if (extensionMatcher.match("GL_EXT_framebuffer_blit"))
444 if (extensionMatcher.match("GL_EXT_packed_depth_stencil"))
446 }
447
448 if (format.version() >= qMakePair(3, 2) || extensionMatcher.match("GL_ARB_geometry_shader4"))
450
451 if (format.version() >= qMakePair(3, 3))
453
454 if (format.version() >= qMakePair(4, 3) || extensionMatcher.match("GL_ARB_invalidate_subdata"))
456
457 if (extensionMatcher.match("GL_ARB_map_buffer_range"))
459
460 if (extensionMatcher.match("GL_EXT_framebuffer_sRGB")) {
461 GLboolean srgbCapableFramebuffers = false;
462 ctx->functions()->glGetBooleanv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgbCapableFramebuffers);
463 if (srgbCapableFramebuffers)
465 }
466
467 if (extensionMatcher.match("GL_ARB_ES3_compatibility"))
469 }
470
471 return extensions;
472}
473
483QOpenGLFunctions::OpenGLFeatures QOpenGLFunctions::openGLFeatures() const
484{
486 if (!d)
487 return { };
488 if (d->m_features == -1)
490 return QOpenGLFunctions::OpenGLFeatures(d->m_features);
491}
492
503{
505 if (!d)
506 return false;
507 if (d->m_features == -1)
509 return (d->m_features & int(feature)) != 0;
510}
511
521QOpenGLExtensions::OpenGLExtensions QOpenGLExtensions::openGLExtensions()
522{
524 if (!d)
525 return { };
526 if (d->m_extensions == -1)
527 d->m_extensions = qt_gl_resolve_extensions();
528 return QOpenGLExtensions::OpenGLExtensions(d->m_extensions);
529}
530
541{
543 if (!d)
544 return false;
545 if (d->m_extensions == -1)
546 d->m_extensions = qt_gl_resolve_extensions();
547 return (d->m_extensions & int(extension)) != 0;
548}
549
562
2067namespace {
2068
2069// this function tries hard to get the opengl function we're looking for by also
2070// trying to resolve it with some of the common extensions if the generic name
2071// can't be found.
2072static QFunctionPointer getProcAddress(QOpenGLContext *context, const char *funcName)
2073{
2074 QFunctionPointer function = context->getProcAddress(funcName);
2075
2076 static const struct {
2077 const char *name;
2078 int len; // includes trailing \0
2079 } extensions[] = {
2080 { "ARB", 4 },
2081 { "OES", 4 },
2082 { "EXT", 4 },
2083 { "ANGLE", 6 },
2084 { "NV", 3 },
2085 };
2086
2087 if (!function) {
2088 char fn[512];
2089 size_t size = strlen(funcName);
2090 Q_ASSERT(size < 500);
2091 memcpy(fn, funcName, size);
2092 char *ext = fn + size;
2093
2094 for (const auto &e : extensions) {
2095 memcpy(ext, e.name, e.len);
2096 function = context->getProcAddress(fn);
2097 if (function)
2098 break;
2099 }
2100 }
2101
2102 return function;
2103}
2104
2105template <typename Func>
2106Func resolve(QOpenGLContext *context, const char *name, Func)
2107{
2108 return reinterpret_cast<Func>(getProcAddress(context, name));
2109}
2110
2111}
2112
2113#define RESOLVE(name) \
2114 resolve(context, "gl"#name, name)
2115
2116#if !QT_CONFIG(opengles2)
2117
2118// some fallback functions
2125
2132
2139
2144
2149
2153
2154#endif // !QT_CONFIG(opengles2)
2155
2156
2158{
2159 init(c);
2160
2161#if !QT_CONFIG(opengles2)
2162 // setup fallbacks in case some methods couldn't get resolved
2163 bool es = QOpenGLContext::currentContext()->isOpenGLES();
2164 if (!f.ClearDepthf || !es)
2165 f.ClearDepthf = qopenglfSpecialClearDepthf;
2166 if (!f.DepthRangef || !es)
2167 f.DepthRangef = qopenglfSpecialDepthRangef;
2168 if (!f.GetShaderPrecisionFormat)
2169 f.GetShaderPrecisionFormat = qopenglfSpecialGetShaderPrecisionFormat;
2170 if (!f.IsProgram)
2171 f.IsProgram = qopenglfSpecialIsProgram;
2172 if (!f.IsShader)
2173 f.IsShader = qopenglfSpecialIsShader;
2174 if (!f.ReleaseShaderCompiler)
2175 f.ReleaseShaderCompiler = qopenglfSpecialReleaseShaderCompiler;
2176#endif
2177}
2178
2179
2181
2182
5025
5040
5046
5048
5051 flushVendorChecked(false)
5052{
5054
5055 MapBuffer = RESOLVE(MapBuffer);
5056 GetBufferSubData = RESOLVE(GetBufferSubData);
5057 DiscardFramebuffer = RESOLVE(DiscardFramebuffer);
5058}
5059
5061{
5062 Q_D(QOpenGLExtensions);
5063 Q_ASSERT(QOpenGLExtensions::isInitialized(d));
5064 Q_ASSERT(d->f.InvalidateFramebuffer || d->DiscardFramebuffer);
5065
5066 // On GLES >= 3 we prefer glInvalidateFramebuffer, even if the
5067 // discard extension is present
5068 if (d->f.InvalidateFramebuffer)
5069 d->f.InvalidateFramebuffer(target, numAttachments, attachments);
5070 else
5071 d->DiscardFramebuffer(target, numAttachments, attachments);
5072
5074}
5075
5077{
5078 Q_D(QOpenGLExtensions);
5079
5080 if (!d->flushVendorChecked) {
5081 d->flushVendorChecked = true;
5082 // It is not quite clear if glFlush() is sufficient to synchronize access to
5083 // resources between sharing contexts in the same thread. On most platforms this
5084 // is enough (e.g. iOS explicitly documents it), while certain drivers only work
5085 // properly when doing glFinish().
5086 d->flushIsSufficientToSyncContexts = false; // default to false, not guaranteed by the spec
5087 const char *vendor = (const char *) glGetString(GL_VENDOR);
5088 if (vendor) {
5089 static const char *const flushEnough[] = { "Apple", "ATI", "Intel", "NVIDIA" };
5090 for (size_t i = 0; i < sizeof(flushEnough) / sizeof(const char *); ++i) {
5091 if (strstr(vendor, flushEnough[i])) {
5093 break;
5094 }
5095 }
5096 }
5097 }
5098
5100 glFlush();
5101 else
5102 glFinish();
5103}
5104
static QPlatformNativeInterface * platformNativeInterface()
static QOpenGLContextGroup * currentContextGroup()
Returns the QOpenGLContextGroup corresponding to the current context.
\inmodule QtGui
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
bool match(const QByteArray &extension) const
Definition qopengl_p.h:34
QOpenGLExtensionsPrivate * d() const
OpenGLExtensions openGLExtensions()
Returns the set of extensions that are present on this system's OpenGL implementation.
bool hasOpenGLExtension(QOpenGLExtensions::OpenGLExtension extension) const
Returns true if extension is present on this system's OpenGL implementation; false otherwise.
void discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
QOpenGLExtraFunctionsPrivate(QOpenGLContext *ctx)
The QOpenGLExtraFunctions class provides cross-platform access to the OpenGL ES 3....
QOpenGLExtraFunctions()
Constructs a default function resolver.
The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API.
OpenGLFeature
This enum defines OpenGL and OpenGL ES features whose presence may depend on the implementation.
QOpenGLFunctionsPrivate * d_ptr
void glFinish()
Convenience function that calls glFinish().
const GLubyte * glGetString(GLenum name)
Convenience function that calls glGetString(name).
void glFlush()
Convenience function that calls glFlush().
QOpenGLFunctions()
Constructs a default function resolver.
void initializeOpenGLFunctions()
Initializes OpenGL function resolution for the current context.
bool hasOpenGLFeature(QOpenGLFunctions::OpenGLFeature feature) const
Returns true if feature is present on this system's OpenGL implementation; false otherwise.
QOpenGLFunctions::OpenGLFeatures openGLFeatures() const
Returns the set of features that are present on this system's OpenGL implementation.
The QOpenGLMultiGroupSharedResource keeps track of a shared resource that might be needed from multip...
The QOpenGLSharedResource class is used to keep track of resources that are shared between OpenGL con...
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6664
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
EGLContext ctx
static VulkanServerBufferGlFunctions * funcs
void extension()
[6]
Definition dialogs.cpp:230
Combined button and popup list for selecting options.
@ CaseInsensitive
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition qlogging.h:166
#define QOPENGLF_APIENTRY
Definition qopengl.h:270
typedef GLint(GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program
GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble zFar
GLdouble GLdouble GLdouble GLdouble GLdouble zNear
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum shadertype
GLenum GLuint GLintptr GLsizeiptr size
[1]
double GLdouble
GLfloat GLfloat f
GLsizei range
typedef GLsizei(GL_APIENTRYP PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target)
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLenum target
GLsizei const GLenum * attachments
GLuint program
typedef GLboolean(GL_APIENTRYP PFNGLISENABLEDIOESPROC)(GLenum target
GLuint name
GLint GLsizei GLsizei GLenum format
GLsizei numAttachments
const GLubyte * c
GLenum precisiontype
const void * getProcAddress
GLuint shader
Definition qopenglext.h:665
GLenum GLsizei len
GLenum GLint GLint * precision
#define QT_OPENGL_EXTRA_FUNCTIONS(F)
#define RESOLVE(name)
#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT
static void QOPENGLF_APIENTRY qopenglfSpecialClearDepthf(GLclampf depth)
static void QOPENGLF_APIENTRY qopenglfSpecialDepthRangef(GLclampf zNear, GLclampf zFar)
static GLboolean QOPENGLF_APIENTRY qopenglfSpecialIsShader(GLuint shader)
#define QT_OPENGL_IMPLEMENT(CLASS, FUNCTIONS)
static void QOPENGLF_APIENTRY qopenglfSpecialGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision)
static int qt_gl_resolve_extensions()
static QOpenGLFunctionsPrivateEx * qt_gl_functions(QOpenGLContext *context=nullptr)
static void QOPENGLF_APIENTRY qopenglfSpecialReleaseShaderCompiler()
static int qt_gl_resolve_features()
static GLboolean QOPENGLF_APIENTRY qopenglfSpecialIsProgram(GLuint program)
#define QT_OPENGL_FUNCTIONS(F)
#define Q_OPENGL_FUNCTIONS_DEBUG
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
static const QQmlJSScope * resolve(const QQmlJSScope *current, const QStringList &names)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GLuint
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_UNUSED(x)
QObject::connect nullptr
QSvgRenderer * renderer
[0]
void freeResource(QOpenGLContext *) override
QOpenGLFunctionsPrivateEx(QOpenGLContext *context)
QOpenGLFunctionsPrivate(QOpenGLContext *ctx)