1 | // Copyright (C) 2016 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 | #ifndef QOPENGLCONTEXT_P_H |
5 | #define QOPENGLCONTEXT_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtGui/private/qtguiglobal_p.h> |
19 | |
20 | #ifndef QT_NO_OPENGL |
21 | |
22 | #include <qopengl.h> |
23 | #include "qopenglcontext.h" |
24 | #include <private/qobject_p.h> |
25 | #include <qmutex.h> |
26 | |
27 | #include <QtCore/QByteArray> |
28 | #include <QtCore/QHash> |
29 | #include <QtCore/QSet> |
30 | |
31 | QT_BEGIN_NAMESPACE |
32 | |
33 | |
34 | class QOpenGLFunctions; |
35 | class QOpenGLContext; |
36 | class QOpenGLFramebufferObject; |
37 | class QOpenGLMultiGroupSharedResource; |
38 | |
39 | class Q_GUI_EXPORT QOpenGLSharedResource |
40 | { |
41 | public: |
42 | QOpenGLSharedResource(QOpenGLContextGroup *group); |
43 | virtual ~QOpenGLSharedResource() = 0; |
44 | |
45 | QOpenGLContextGroup *group() const { return m_group; } |
46 | |
47 | // schedule the resource for deletion at an appropriate time |
48 | void free(); |
49 | |
50 | protected: |
51 | // the resource's share group no longer exists, invalidate the resource |
52 | virtual void invalidateResource() = 0; |
53 | |
54 | // a valid context in the group is current, free the resource |
55 | virtual void freeResource(QOpenGLContext *context) = 0; |
56 | |
57 | private: |
58 | QOpenGLContextGroup *m_group; |
59 | |
60 | friend class QOpenGLContextGroup; |
61 | friend class QOpenGLContextGroupPrivate; |
62 | friend class QOpenGLMultiGroupSharedResource; |
63 | |
64 | Q_DISABLE_COPY_MOVE(QOpenGLSharedResource) |
65 | }; |
66 | |
67 | class Q_GUI_EXPORT QOpenGLSharedResourceGuard : public QOpenGLSharedResource |
68 | { |
69 | public: |
70 | typedef void (*FreeResourceFunc)(QOpenGLFunctions *functions, GLuint id); |
71 | QOpenGLSharedResourceGuard(QOpenGLContext *context, GLuint id, FreeResourceFunc func) |
72 | : QOpenGLSharedResource(context->shareGroup()) |
73 | , m_id(id) |
74 | , m_func(func) |
75 | { |
76 | } |
77 | ~QOpenGLSharedResourceGuard() override; |
78 | |
79 | GLuint id() const { return m_id; } |
80 | |
81 | protected: |
82 | void invalidateResource() override |
83 | { |
84 | m_id = 0; |
85 | } |
86 | |
87 | void freeResource(QOpenGLContext *context) override; |
88 | |
89 | private: |
90 | GLuint m_id; |
91 | FreeResourceFunc m_func; |
92 | }; |
93 | |
94 | class Q_GUI_EXPORT QOpenGLContextGroupPrivate : public QObjectPrivate |
95 | { |
96 | Q_DECLARE_PUBLIC(QOpenGLContextGroup) |
97 | public: |
98 | QOpenGLContextGroupPrivate() |
99 | : m_context(nullptr) |
100 | , m_refs(0) |
101 | { |
102 | } |
103 | ~QOpenGLContextGroupPrivate() override; |
104 | |
105 | void addContext(QOpenGLContext *ctx); |
106 | void removeContext(QOpenGLContext *ctx); |
107 | |
108 | void cleanup(); |
109 | |
110 | void deletePendingResources(QOpenGLContext *ctx); |
111 | |
112 | QOpenGLContext *m_context; |
113 | |
114 | QList<QOpenGLContext *> m_shares; |
115 | QRecursiveMutex m_mutex; |
116 | |
117 | QHash<QOpenGLMultiGroupSharedResource *, QOpenGLSharedResource *> m_resources; |
118 | QAtomicInt m_refs; |
119 | |
120 | QList<QOpenGLSharedResource *> m_sharedResources; |
121 | QList<QOpenGLSharedResource *> m_pendingDeletion; |
122 | }; |
123 | |
124 | class Q_GUI_EXPORT QOpenGLMultiGroupSharedResource |
125 | { |
126 | public: |
127 | QOpenGLMultiGroupSharedResource(); |
128 | ~QOpenGLMultiGroupSharedResource(); |
129 | |
130 | void insert(QOpenGLContext *context, QOpenGLSharedResource *value); |
131 | void cleanup(QOpenGLContextGroup *group, QOpenGLSharedResource *value); |
132 | |
133 | QOpenGLSharedResource *value(QOpenGLContext *context); |
134 | |
135 | QList<QOpenGLSharedResource *> resources() const; |
136 | |
137 | template <typename T> |
138 | T *value(QOpenGLContext *context) { |
139 | QOpenGLContextGroup *group = context->shareGroup(); |
140 | // Have to use our own mutex here, not the group's, since |
141 | // m_groups has to be protected too against any concurrent access. |
142 | QMutexLocker locker(&m_mutex); |
143 | T *resource = static_cast<T *>(group->d_func()->m_resources.value(key: this, defaultValue: nullptr)); |
144 | if (!resource) { |
145 | resource = new T(context); |
146 | insert(context, value: resource); |
147 | } |
148 | return resource; |
149 | } |
150 | |
151 | private: |
152 | QAtomicInt active; |
153 | QList<QOpenGLContextGroup *> m_groups; |
154 | QRecursiveMutex m_mutex; |
155 | }; |
156 | |
157 | class QPaintEngineEx; |
158 | class QOpenGLFunctions; |
159 | class QOpenGLTextureHelper; |
160 | class QOpenGLVertexArrayObjectHelper; |
161 | |
162 | class Q_GUI_EXPORT QOpenGLContextVersionFunctionHelper |
163 | { |
164 | public: |
165 | virtual ~QOpenGLContextVersionFunctionHelper(); |
166 | }; |
167 | |
168 | class Q_GUI_EXPORT QOpenGLContextPrivate : public QObjectPrivate |
169 | { |
170 | Q_DECLARE_PUBLIC(QOpenGLContext) |
171 | public: |
172 | QOpenGLContextPrivate() |
173 | : platformGLContext(nullptr) |
174 | , shareContext(nullptr) |
175 | , shareGroup(nullptr) |
176 | , screen(nullptr) |
177 | , surface(nullptr) |
178 | , functions(nullptr) |
179 | , textureFunctions(nullptr) |
180 | , versionFunctions(nullptr) |
181 | , vaoHelper(nullptr) |
182 | , vaoHelperDestroyCallback(nullptr) |
183 | , max_texture_size(-1) |
184 | , workaround_brokenFBOReadBack(false) |
185 | , workaround_brokenTexSubImage(false) |
186 | , workaround_missingPrecisionQualifiers(false) |
187 | , active_engine(nullptr) |
188 | , qgl_current_fbo_invalid(false) |
189 | , qgl_current_fbo(nullptr) |
190 | , defaultFboRedirect(0) |
191 | { |
192 | requestedFormat = QSurfaceFormat::defaultFormat(); |
193 | } |
194 | |
195 | ~QOpenGLContextPrivate() override; |
196 | |
197 | void adopt(QPlatformOpenGLContext *); |
198 | |
199 | QSurfaceFormat requestedFormat; |
200 | QPlatformOpenGLContext *platformGLContext; |
201 | QOpenGLContext *shareContext; |
202 | QOpenGLContextGroup *shareGroup; |
203 | QScreen *screen; |
204 | QSurface *surface; |
205 | QOpenGLFunctions *functions; |
206 | mutable QSet<QByteArray> extensionNames; |
207 | QOpenGLTextureHelper* textureFunctions; |
208 | std::function<void()> textureFunctionsDestroyCallback; |
209 | QOpenGLContextVersionFunctionHelper *versionFunctions; |
210 | QOpenGLVertexArrayObjectHelper *vaoHelper; |
211 | using QOpenGLVertexArrayObjectHelperDestroyCallback_t = void (*)(QOpenGLVertexArrayObjectHelper *); |
212 | QOpenGLVertexArrayObjectHelperDestroyCallback_t vaoHelperDestroyCallback; |
213 | |
214 | GLint max_texture_size; |
215 | |
216 | bool workaround_brokenFBOReadBack; |
217 | bool workaround_brokenTexSubImage; |
218 | bool workaround_missingPrecisionQualifiers; |
219 | |
220 | QPaintEngineEx *active_engine; |
221 | |
222 | bool qgl_current_fbo_invalid; |
223 | |
224 | // Set and unset in QOpenGLFramebufferObject::bind()/unbind(). |
225 | // (Only meaningful for QOGLFBO since an FBO might be bound by other means) |
226 | // Saves us from querying the driver for the current FBO in most paths. |
227 | QOpenGLFramebufferObject *qgl_current_fbo; |
228 | |
229 | GLuint defaultFboRedirect; |
230 | |
231 | static QOpenGLContext *setCurrentContext(QOpenGLContext *context); |
232 | |
233 | int maxTextureSize(); |
234 | |
235 | static QOpenGLContextPrivate *get(QOpenGLContext *context) |
236 | { |
237 | return context ? context->d_func() : nullptr; |
238 | } |
239 | |
240 | #if !defined(QT_NO_DEBUG) |
241 | static bool toggleMakeCurrentTracker(QOpenGLContext *context, bool value) |
242 | { |
243 | QMutexLocker locker(&makeCurrentTrackerMutex); |
244 | bool old = makeCurrentTracker.value(key: context, defaultValue: false); |
245 | makeCurrentTracker.insert(key: context, value); |
246 | return old; |
247 | } |
248 | static void cleanMakeCurrentTracker(QOpenGLContext *context) |
249 | { |
250 | QMutexLocker locker(&makeCurrentTrackerMutex); |
251 | makeCurrentTracker.remove(key: context); |
252 | } |
253 | static QHash<QOpenGLContext *, bool> makeCurrentTracker; |
254 | static QMutex makeCurrentTrackerMutex; |
255 | #endif |
256 | |
257 | void _q_screenDestroyed(QObject *object); |
258 | }; |
259 | |
260 | Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); |
261 | Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); |
262 | |
263 | QT_END_NAMESPACE |
264 | |
265 | #endif // QT_NO_OPENGL |
266 | #endif // QOPENGLCONTEXT_P_H |
267 | |