1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QOPENGLCONTEXT_P_H
41 #define QOPENGLCONTEXT_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtGui/private/qtguiglobal_p.h>
55 
56 #ifndef QT_NO_OPENGL
57 
58 #include <qopengl.h>
59 #include "qopenglcontext.h"
60 #include <private/qobject_p.h>
61 #include <qmutex.h>
62 
63 #include <QtCore/QByteArray>
64 #include <QtCore/QHash>
65 #include <QtCore/QSet>
66 
67 QT_BEGIN_NAMESPACE
68 
69 
70 class QOpenGLFunctions;
71 class QOpenGLContext;
72 class QOpenGLFramebufferObject;
73 class QOpenGLMultiGroupSharedResource;
74 
75 class Q_GUI_EXPORT QOpenGLSharedResource
76 {
77 public:
78     QOpenGLSharedResource(QOpenGLContextGroup *group);
79     virtual ~QOpenGLSharedResource() = 0;
80 
group()81     QOpenGLContextGroup *group() const { return m_group; }
82 
83     // schedule the resource for deletion at an appropriate time
84     void free();
85 
86 protected:
87     // the resource's share group no longer exists, invalidate the resource
88     virtual void invalidateResource() = 0;
89 
90     // a valid context in the group is current, free the resource
91     virtual void freeResource(QOpenGLContext *context) = 0;
92 
93 private:
94     QOpenGLContextGroup *m_group;
95 
96     friend class QOpenGLContextGroup;
97     friend class QOpenGLContextGroupPrivate;
98     friend class QOpenGLMultiGroupSharedResource;
99 
100     Q_DISABLE_COPY_MOVE(QOpenGLSharedResource)
101 };
102 
103 class Q_GUI_EXPORT QOpenGLSharedResourceGuard : public QOpenGLSharedResource
104 {
105 public:
106     typedef void (*FreeResourceFunc)(QOpenGLFunctions *functions, GLuint id);
QOpenGLSharedResourceGuard(QOpenGLContext * context,GLuint id,FreeResourceFunc func)107     QOpenGLSharedResourceGuard(QOpenGLContext *context, GLuint id, FreeResourceFunc func)
108         : QOpenGLSharedResource(context->shareGroup())
109         , m_id(id)
110         , m_func(func)
111     {
112     }
113 
id()114     GLuint id() const { return m_id; }
115 
116 protected:
invalidateResource()117     void invalidateResource() override
118     {
119         m_id = 0;
120     }
121 
122     void freeResource(QOpenGLContext *context) override;
123 
124 private:
125     GLuint m_id;
126     FreeResourceFunc m_func;
127 };
128 
129 class Q_GUI_EXPORT QOpenGLContextGroupPrivate : public QObjectPrivate
130 {
Q_DECLARE_PUBLIC(QOpenGLContextGroup)131     Q_DECLARE_PUBLIC(QOpenGLContextGroup)
132 public:
133     QOpenGLContextGroupPrivate()
134         : m_context(nullptr)
135         , m_refs(0)
136     {
137     }
138 
139     void addContext(QOpenGLContext *ctx);
140     void removeContext(QOpenGLContext *ctx);
141 
142     void cleanup();
143 
144     void deletePendingResources(QOpenGLContext *ctx);
145 
146     QOpenGLContext *m_context;
147 
148     QList<QOpenGLContext *> m_shares;
149     QRecursiveMutex m_mutex;
150 
151     QHash<QOpenGLMultiGroupSharedResource *, QOpenGLSharedResource *> m_resources;
152     QAtomicInt m_refs;
153 
154     QList<QOpenGLSharedResource *> m_sharedResources;
155     QList<QOpenGLSharedResource *> m_pendingDeletion;
156 };
157 
158 class Q_GUI_EXPORT QOpenGLMultiGroupSharedResource
159 {
160 public:
161     QOpenGLMultiGroupSharedResource();
162     ~QOpenGLMultiGroupSharedResource();
163 
164     void insert(QOpenGLContext *context, QOpenGLSharedResource *value);
165     void cleanup(QOpenGLContextGroup *group, QOpenGLSharedResource *value);
166 
167     QOpenGLSharedResource *value(QOpenGLContext *context);
168 
169     QList<QOpenGLSharedResource *> resources() const;
170 
171     template <typename T>
value(QOpenGLContext * context)172     T *value(QOpenGLContext *context) {
173         QOpenGLContextGroup *group = context->shareGroup();
174         // Have to use our own mutex here, not the group's, since
175         // m_groups has to be protected too against any concurrent access.
176         QMutexLocker locker(&m_mutex);
177         T *resource = static_cast<T *>(group->d_func()->m_resources.value(this, 0));
178         if (!resource) {
179             resource = new T(context);
180             insert(context, resource);
181         }
182         return resource;
183     }
184 
185 private:
186     QAtomicInt active;
187     QList<QOpenGLContextGroup *> m_groups;
188     QRecursiveMutex m_mutex;
189 };
190 
191 class QPaintEngineEx;
192 class QOpenGLFunctions;
193 class QOpenGLTextureHelper;
194 
195 class Q_GUI_EXPORT QOpenGLContextPrivate : public QObjectPrivate
196 {
Q_DECLARE_PUBLIC(QOpenGLContext)197     Q_DECLARE_PUBLIC(QOpenGLContext)
198 public:
199     QOpenGLContextPrivate()
200         : qGLContextHandle(nullptr)
201         , qGLContextDeleteFunction(nullptr)
202         , platformGLContext(nullptr)
203         , shareContext(nullptr)
204         , shareGroup(nullptr)
205         , screen(nullptr)
206         , surface(nullptr)
207         , functions(nullptr)
208         , textureFunctions(nullptr)
209         , max_texture_size(-1)
210         , workaround_brokenFBOReadBack(false)
211         , workaround_brokenTexSubImage(false)
212         , workaround_missingPrecisionQualifiers(false)
213         , active_engine(nullptr)
214         , qgl_current_fbo_invalid(false)
215         , qgl_current_fbo(nullptr)
216         , defaultFboRedirect(0)
217     {
218         requestedFormat = QSurfaceFormat::defaultFormat();
219     }
220 
~QOpenGLContextPrivate()221     ~QOpenGLContextPrivate()
222     {
223         //do not delete the QOpenGLContext handle here as it is deleted in
224         //QWidgetPrivate::deleteTLSysExtra()
225     }
226 
227     mutable QHash<QOpenGLVersionProfile, QAbstractOpenGLFunctions *> versionFunctions;
228     mutable QOpenGLVersionFunctionsStorage versionFunctionsStorage;
229     mutable QSet<QAbstractOpenGLFunctions *> externalVersionFunctions;
230 
231     void *qGLContextHandle;
232     void (*qGLContextDeleteFunction)(void *handle);
233 
234     QSurfaceFormat requestedFormat;
235     QPlatformOpenGLContext *platformGLContext;
236     QOpenGLContext *shareContext;
237     QOpenGLContextGroup *shareGroup;
238     QScreen *screen;
239     QSurface *surface;
240     QOpenGLFunctions *functions;
241     mutable QSet<QByteArray> extensionNames;
242     QOpenGLTextureHelper* textureFunctions;
243 
244     GLint max_texture_size;
245 
246     bool workaround_brokenFBOReadBack;
247     bool workaround_brokenTexSubImage;
248     bool workaround_missingPrecisionQualifiers;
249 
250     QPaintEngineEx *active_engine;
251 
252     bool qgl_current_fbo_invalid;
253 
254     // Set and unset in QOpenGLFramebufferObject::bind()/unbind().
255     // (Only meaningful for QOGLFBO since an FBO might be bound by other means)
256     // Saves us from querying the driver for the current FBO in most paths.
257     QOpenGLFramebufferObject *qgl_current_fbo;
258 
259     QVariant nativeHandle;
260     GLuint defaultFboRedirect;
261 
262     static QOpenGLContext *setCurrentContext(QOpenGLContext *context);
263 
264     int maxTextureSize();
265 
get(QOpenGLContext * context)266     static QOpenGLContextPrivate *get(QOpenGLContext *context)
267     {
268         return context ? context->d_func() : nullptr;
269     }
270 
271 #if !defined(QT_NO_DEBUG)
toggleMakeCurrentTracker(QOpenGLContext * context,bool value)272     static bool toggleMakeCurrentTracker(QOpenGLContext *context, bool value)
273     {
274         QMutexLocker locker(&makeCurrentTrackerMutex);
275         bool old = makeCurrentTracker.value(context, false);
276         makeCurrentTracker.insert(context, value);
277         return old;
278     }
cleanMakeCurrentTracker(QOpenGLContext * context)279     static void cleanMakeCurrentTracker(QOpenGLContext *context)
280     {
281         QMutexLocker locker(&makeCurrentTrackerMutex);
282         makeCurrentTracker.remove(context);
283     }
284     static QHash<QOpenGLContext *, bool> makeCurrentTracker;
285     static QMutex makeCurrentTrackerMutex;
286 #endif
287 
288     void _q_screenDestroyed(QObject *object);
289 };
290 
291 Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
292 Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context();
293 
294 QT_END_NAMESPACE
295 
296 #endif // QT_NO_OPENGL
297 #endif // QOPENGLCONTEXT_P_H
298