1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt WebGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
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 General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include "qwebglcontext.h"
31 
32 #include "qwebglfunctioncall.h"
33 #include "qwebglintegration.h"
34 #include "qwebglintegration_p.h"
35 #include "qwebglwebsocketserver.h"
36 #include "qwebglwindow.h"
37 #include "qwebglwindow_p.h"
38 
39 #include <QtCore/qhash.h>
40 #include <QtCore/qpair.h>
41 #include <QtCore/qrect.h>
42 #include <QtCore/qset.h>
43 #include <QtGui/private/qguiapplication_p.h>
44 #include <QtGui/private/qopenglcontext_p.h>
45 #include <QtGui/qguiapplication.h>
46 #include <QtGui/qimage.h>
47 #include <QtGui/qopenglcontext.h>
48 #include <QtGui/qsurface.h>
49 #include <QtWebSockets/qwebsocket.h>
50 
51 #include <cstring>
52 #include <limits>
53 
54 QT_BEGIN_NAMESPACE
55 
56 static Q_LOGGING_CATEGORY(lc, "qt.qpa.webgl.context")
57 
58 class QWebGLContextPrivate
59 {
60 public:
61     static QAtomicInt nextId;
62     static QSet<int> waitingIds;
63     union { int id = -1; qintptr padded; };
64     QPlatformSurface *currentSurface = nullptr;
65     QSurfaceFormat surfaceFormat;
66 };
67 
68 QAtomicInt QWebGLContextPrivate::nextId(1);
69 QSet<int> QWebGLContextPrivate::waitingIds;
70 
71 struct PixelStorageModes
72 {
PixelStorageModesPixelStorageModes73     PixelStorageModes() : unpackAlignment(4) { }
74     int unpackAlignment;
75 };
76 
77 struct ContextData {
78     GLuint currentProgram = 0;
79     GLuint boundArrayBuffer = 0;
80     GLuint boundElementArrayBuffer = 0;
81     GLuint boundTexture2D = 0;
82     GLenum activeTextureUnit = GL_TEXTURE0;
83     GLuint boundDrawFramebuffer = 0;
84 //    GLuint boundReadFramebuffer = 0;
85     GLuint unpackAlignment = 4;
86     struct VertexAttrib {
VertexAttribContextData::VertexAttrib87         VertexAttrib() : arrayBufferBinding(0), pointer(nullptr), enabled(false) { }
88         GLuint arrayBufferBinding;
89         const void *pointer;
90         bool enabled;
91         GLint size;
92         GLenum type;
93         bool normalized;
94         GLsizei stride;
95     };
96     QHash<GLuint, VertexAttrib> vertexAttribPointers;
97     QHash<GLuint, QImage> images;
98     PixelStorageModes pixelStorage;
99     QMap<GLenum, QVariant> cachedParameters;
100     QSet<QByteArray> stringCache;
101 };
102 
103 static QHash<int, ContextData> s_contextData;
104 
currentContext()105 QWebGLContext *currentContext()
106 {
107     auto context = QOpenGLContext::currentContext();
108     if (context)
109         return static_cast<QWebGLContext *>(context->handle());
110     return nullptr;
111 }
112 
currentContextData()113 ContextData *currentContextData()
114 {
115     auto context = currentContext();
116     if (context)
117         return &s_contextData[context->id()];
118     return nullptr;
119 }
120 
imageSize(GLsizei width,GLsizei height,GLenum format,GLenum type,const PixelStorageModes & pixelStorage)121 inline int imageSize(GLsizei width, GLsizei height, GLenum format, GLenum type,
122                      const PixelStorageModes &pixelStorage)
123 {
124     Q_UNUSED(pixelStorage); // TODO: Support different pixelStorage formats
125 
126     static struct BppTabEntry {
127         GLenum format;
128         GLenum type;
129         int bytesPerPixel;
130     } bppTab[] = {
131         { GL_RGBA, GL_UNSIGNED_BYTE, 4 },
132         { GL_RGBA, GL_BYTE, 4 },
133         { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 2 },
134         { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 2 },
135         { GL_RGBA, GL_FLOAT, 16 },
136         { GL_RGB, GL_UNSIGNED_BYTE, 3 },
137         { GL_RGB, GL_BYTE, 3 },
138         { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 2 },
139         { GL_RGB, GL_FLOAT, 12 },
140 
141         { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 2 },
142         { GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 4 },
143         { GL_DEPTH_COMPONENT, GL_FLOAT, 4 },
144 
145         { GL_RGBA, GL_UNSIGNED_BYTE, 4 },
146         { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 2 },
147         { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 2 },
148         { GL_RGB, GL_UNSIGNED_BYTE, 3 },
149         { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 2 },
150         { GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 2 },
151         { GL_LUMINANCE, GL_UNSIGNED_BYTE, 1 },
152         { GL_ALPHA, GL_UNSIGNED_BYTE, 1 },
153 
154         { GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4 },
155         { GL_BGRA_EXT, GL_BYTE, 4 },
156         { GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4, 2 },
157         { GL_BGRA_EXT, GL_UNSIGNED_SHORT_5_5_5_1, 2 },
158         { GL_BGRA_EXT, GL_FLOAT, 16 }
159     };
160 
161     int bytesPerPixel = 0;
162     for (size_t i = 0; i < sizeof(bppTab) / sizeof(BppTabEntry); ++i) {
163         if (bppTab[i].format == format && bppTab[i].type == type) {
164             bytesPerPixel = bppTab[i].bytesPerPixel;
165             break;
166         }
167     }
168 
169     const int rowSize = width * bytesPerPixel;
170     if (!bytesPerPixel)
171         qCWarning(lc, "Unknown texture format %x - %x", format, type);
172 
173     return rowSize * height;
174 }
175 
lockMutex()176 static void lockMutex()
177 {
178     QWebGLIntegrationPrivate::instance()->webSocketServer->mutex()->lock();
179 }
180 
waitCondition(unsigned long time=ULONG_MAX)181 static void waitCondition(unsigned long time = ULONG_MAX)
182 {
183     auto mutex = QWebGLIntegrationPrivate::instance()->webSocketServer->mutex();
184     auto waitCondition = QWebGLIntegrationPrivate::instance()->webSocketServer->waitCondition();
185     waitCondition->wait(mutex, time);
186 }
187 
unlockMutex()188 static void unlockMutex()
189 {
190     auto mutex = QWebGLIntegrationPrivate::instance()->webSocketServer->mutex();
191     mutex->unlock();
192 }
193 
elementSize(GLenum type)194 static int elementSize(GLenum type)
195 {
196     switch (type) {
197     case GL_SHORT:
198     case GL_UNSIGNED_SHORT:
199         return 2;
200     case GL_FLOAT:
201     case GL_FIXED:
202     case GL_INT:
203     case GL_UNSIGNED_INT:
204         return 4;
205     default:
206         return 1;
207     }
208 }
209 
vertexSize(GLint elementsPerVertex,GLenum type)210 static int vertexSize(GLint elementsPerVertex, GLenum type)
211 {
212     return elementSize(type) * elementsPerVertex;
213 }
214 
bufferSize(GLsizei count,GLint elemsPerVertex,GLenum type,GLsizei stride)215 static int bufferSize(GLsizei count, GLint elemsPerVertex, GLenum type, GLsizei stride)
216 {
217     if (count == 0)
218         return 0;
219 
220     int vsize = vertexSize(elemsPerVertex, type);
221 
222     if (stride == 0)
223         stride = vsize;
224 
225     return vsize + (count - 1) * stride;
226 }
227 
setVertexAttribs(QWebGLFunctionCall * event,GLsizei count)228 static void setVertexAttribs(QWebGLFunctionCall *event, GLsizei count)
229 {
230     event->addInt(currentContextData()->vertexAttribPointers.count());
231     const auto &vertexAttribPointers = currentContextData()->vertexAttribPointers;
232     for (auto it = vertexAttribPointers.cbegin(), end = vertexAttribPointers.cend(); it != end; ++it) {
233         const ContextData::VertexAttrib &va(it.value());
234         if (va.arrayBufferBinding == 0 && va.enabled) {
235             int len = bufferSize(count, va.size, va.type, va.stride);
236             event->addParameters(it.key(), va.size, int(va.type), va.normalized, va.stride);
237             // found an enabled vertex attribute that was specified with a client-side pointer
238             event->addData(QByteArray(reinterpret_cast<const char *>(va.pointer), len));
239         }
240     }
241 }
242 
243 template<class POINTER, class COUNT>
addHelper(QWebGLFunctionCall * event,const QPair<POINTER,COUNT> & elements)244 inline QWebGLFunctionCall *addHelper(QWebGLFunctionCall *event,
245                                      const QPair<POINTER, COUNT> &elements)
246 {
247     QVariantList list;
248     for (auto i = 0; i < elements.second; ++i)
249         list.append(QVariant::fromValue(elements.first[i]));
250     event->addList(list);
251     return event;
252 }
253 
254 template<class SIZE>
addHelper(QWebGLFunctionCall * event,const QPair<const float *,SIZE> & elements)255 inline void addHelper(QWebGLFunctionCall *event, const QPair<const float *, SIZE> &elements)
256 {
257     QVariantList list;
258     for (auto i = 0; i < elements.second; ++i)
259         list.append(QVariant::fromValue<double>(elements.first[i]));
260     event->addList(list);
261 }
262 
263 template<class T>
addHelper(QWebGLFunctionCall * event,const T & value)264 inline QWebGLFunctionCall *addHelper(QWebGLFunctionCall *event, const T &value)
265 {
266     if (event)
267         event->add(value);
268     return event;
269 }
270 
271 template<class T, class... Ts>
addHelper(QWebGLFunctionCall * event,const T & value,const Ts &...rest)272 inline QWebGLFunctionCall *addHelper(QWebGLFunctionCall *event, const T &value, const Ts&... rest)
273 {
274     if (event) {
275         event->add(value);
276         addHelper(event, rest...);
277     }
278     return event;
279 }
280 
281 template<class T>
queryValue(int id,const T & defaultValue=T ())282 static T queryValue(int id, const T &defaultValue = T())
283 {
284     const auto variant = currentContext()->queryValue(id);
285     if (variant.isNull())
286         return defaultValue;
287     if (!variant.canConvert<T>()) {
288         qCWarning(lc, "Cannot convert %s to " QT_STRINGIFY(T), variant.typeName());
289         return defaultValue;
290     }
291     return variant.value<T>();
292 }
293 
294 template<typename T>
295 struct ParameterTypeTraits {
typeIdParameterTypeTraits296     static int typeId() { return qMetaTypeId<T>(); }
isArrayParameterTypeTraits297     static bool isArray() { return std::is_pointer<T>(); }
298 };
299 
300 template<typename T>
301 struct ParameterTypeTraits<T*> : ParameterTypeTraits<T> {
typeIdParameterTypeTraits302     static int typeId() { return qMetaTypeId<T>(); }
303 };
304 
305 template<typename T>
306 struct ParameterTypeTraits<const T*> : ParameterTypeTraits<T*> {
307 };
308 
309 template<typename T>
310 struct ParameterTypeTraits<const T**> : ParameterTypeTraits<T*> {
311 };
312 
313 struct GLFunction
314 {
315     struct Parameter {
ParameterGLFunction::Parameter316         Parameter() {}
ParameterGLFunction::Parameter317         Parameter(const QString &name, const QString &typeName, int typeId, bool isArray) :
318             name(name), typeName(typeName), typeId(typeId), isArray(isArray) {}
319 
320         QString name;
321         QString typeName;
322         int typeId;
323         bool isArray;
324     };
325 
326     static QHash<QString, const GLFunction *> byName;
327     static QStringList remoteFunctionNames;
328     using ParameterList = QVector<Parameter>;
329 
GLFunctionGLFunction330     GLFunction(const QString &remoteName,
331                const QString &localName,
332                QFunctionPointer functionPointer,
333                ParameterList parameters = ParameterList())
334         : remoteName(remoteName), localName(localName),
335           functionPointer(functionPointer), parameters(parameters)
336     {
337         Q_ASSERT(!byName.contains(localName));
338         byName.insert(localName, this);
339         id = remoteFunctionNames.size();
340         Q_ASSERT(remoteFunctionNames.size() <= std::numeric_limits<quint8>::max());
341         remoteFunctionNames.append(remoteName);
342         Q_ASSERT(byName.size() == remoteFunctionNames.size());
343     }
344 
GLFunctionGLFunction345     GLFunction(const QString &name) : GLFunction(name, name, nullptr)
346     {}
347     quint8 id;
348     const QString remoteName;
349     const QString localName;
350     const QFunctionPointer functionPointer;
351     const ParameterList parameters;
352 };
353 
354 QHash<QString, const GLFunction *> GLFunction::byName;
355 QStringList GLFunction::remoteFunctionNames;
356 
357 template<const GLFunction *Function>
createEventImpl(bool wait)358 static QWebGLFunctionCall *createEventImpl(bool wait)
359 {
360     auto context = QOpenGLContext::currentContext();
361     Q_ASSERT(context);
362     const auto handle = static_cast<QWebGLContext *>(context->handle());
363     auto integrationPrivate = QWebGLIntegrationPrivate::instance();
364     const auto clientData = integrationPrivate->findClientData(handle->currentSurface());
365     if (!clientData || !clientData->socket
366             || clientData->socket->state() != QAbstractSocket::ConnectedState)
367         return nullptr;
368     return new QWebGLFunctionCall(Function->localName, handle->currentSurface(), wait);
369 }
370 
postEventImpl(QWebGLFunctionCall * event)371 static void postEventImpl(QWebGLFunctionCall *event)
372 {
373     if (event->isBlocking())
374         QWebGLContextPrivate::waitingIds.insert(event->id());
375     QCoreApplication::postEvent(QWebGLIntegrationPrivate::instance()->webSocketServer, event);
376 }
377 
378 template<const GLFunction *Function, class... Ts>
createEventAndPostImpl(bool wait,Ts &&...arguments)379 static int createEventAndPostImpl(bool wait, Ts&&... arguments)
380 {
381     auto event = createEventImpl<Function>(wait);
382     auto id = -1;
383     if (event) {
384         id = event->id();
385         addHelper(event, arguments...);
386         postEventImpl(event);
387     }
388     return id;
389 }
390 
391 template<const GLFunction *Function>
createEventAndPostImpl(bool wait)392 static int createEventAndPostImpl(bool wait)
393 {
394     auto event = createEventImpl<Function>(wait);
395     auto id = -1;
396     if (event) {
397         id = event->id();
398         postEventImpl(event);
399     }
400     return id;
401 }
402 
403 template<const GLFunction *Function, class... Ts>
postEventImpl(bool wait,Ts &&...arguments)404 inline int postEventImpl(bool wait, Ts&&... arguments)
405 {
406     return createEventAndPostImpl<Function>(wait, arguments...);
407 }
408 
409 template<const GLFunction *Function>
postEvent(bool wait)410 inline int postEvent(bool wait)
411 {
412     return createEventAndPostImpl<Function>(wait);
413 }
414 
415 template<const GLFunction *Function, class...Ts>
postEvent(Ts &&...arguments)416 inline int postEvent(Ts&&... arguments)
417 {
418     return postEventImpl<Function>(false, arguments...);
419 }
420 
421 template<const GLFunction *Function, class ReturnType, class...Ts>
postEventAndQuery(ReturnType defaultValue,Ts &&...arguments)422 static ReturnType postEventAndQuery(ReturnType defaultValue,
423                                     Ts&&... arguments)
424 {
425     auto id = postEventImpl<Function>(true, arguments...);
426     return id != -1 ? queryValue(id, defaultValue) : defaultValue;
427 }
428 
429 namespace QWebGL {
430 #define EXPAND(x) x
431 
432 #define USE_(...) __VA_ARGS__
433 #define IGNORE_(...)
434 
435 
436 // Retrieve the type
437 // TYPEOF( (type) name ) -> TYPEOF_( SEPARATE (type) name ) -> FIRST_ARG( type, name ) -> type
438 #define FIRST_ARG(ONE, ...) ONE
439 #define SEPARATE(ITEM) ITEM,
440 #define TYPEOF_(...) EXPAND(FIRST_ARG(__VA_ARGS__))
441 #define TYPEOF(ITEM) TYPEOF_(SEPARATE ITEM)
442 
443 // Strip off the type, leaving just the parameter name:
444 #define STRIP(ITEM) IGNORE_ ITEM
445 // PAIR( (type) name ) -> type name
446 #define PAIR(ITEM) USE_ ITEM
447 
448 // Make a FOREACH macro
449 #define FOR_1(EACH, ITEM) EACH(ITEM)
450 #define FOR_2(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_1(EACH, __VA_ARGS__))
451 #define FOR_3(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_2(EACH, __VA_ARGS__))
452 #define FOR_4(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_3(EACH, __VA_ARGS__))
453 #define FOR_5(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_4(EACH, __VA_ARGS__))
454 #define FOR_6(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_5(EACH, __VA_ARGS__))
455 #define FOR_7(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_6(EACH, __VA_ARGS__))
456 #define FOR_8(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_7(EACH, __VA_ARGS__))
457 #define FOR_9(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_8(EACH, __VA_ARGS__))
458 #define FOR_10(EACH, ITEM, ...) EACH(ITEM), EXPAND(FOR_9(EACH, __VA_ARGS__))
459 //... repeat as needed
460 
461 #define SELECT_BY_COUNT(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, NAME, ...) NAME
462 #define FOR_EACH(action, ...) \
463   EXPAND(SELECT_BY_COUNT(__VA_ARGS__, FOR_10, FOR_9, FOR_8, FOR_7, \
464     FOR_6, FOR_5, FOR_4, FOR_3, FOR_2, FOR_1)(action, __VA_ARGS__))
465 
466 #define QWEBGL_FUNCTION_PARAMETER(ITEM) \
467     GLFunction::Parameter { \
468         QStringLiteral(QT_STRINGIFY(STRIP(ITEM))), \
469         QStringLiteral(QT_STRINGIFY(TYPEOF(ITEM))), \
470         ParameterTypeTraits<TYPEOF(ITEM)>::typeId(), \
471         ParameterTypeTraits<TYPEOF(ITEM)>::isArray() \
472     }
473 
474 #if defined(Q_CC_MSVC) && defined(Q_OS_WIN32) && !defined(Q_OS_WIN64)
475 #   define WEBGL_APIENTRY __stdcall
476 #else
477 #   define WEBGL_APIENTRY
478 #endif
479 
480 #define QWEBGL_FUNCTION(REMOTE_NAME, RET_TYPE, LOCAL_NAME, ...) \
481     RET_TYPE WEBGL_APIENTRY LOCAL_NAME(FOR_EACH(TYPEOF, __VA_ARGS__));\
482     extern const GLFunction REMOTE_NAME { \
483         #REMOTE_NAME, \
484         #LOCAL_NAME, \
485         reinterpret_cast<QFunctionPointer>(LOCAL_NAME), \
486         GLFunction::ParameterList({FOR_EACH(QWEBGL_FUNCTION_PARAMETER, __VA_ARGS__)}) \
487     }; \
488     RET_TYPE WEBGL_APIENTRY LOCAL_NAME(FOR_EACH(PAIR, __VA_ARGS__))
489 
490 #define QWEBGL_FUNCTION_NO_PARAMS(REMOTE_NAME, RET_TYPE, LOCAL_NAME) \
491     RET_TYPE WEBGL_APIENTRY LOCAL_NAME();\
492     extern const GLFunction REMOTE_NAME { \
493         #REMOTE_NAME, \
494         #LOCAL_NAME, \
495         (QFunctionPointer) LOCAL_NAME \
496     }; \
497     RET_TYPE WEBGL_APIENTRY LOCAL_NAME()
498 
499 #define QWEBGL_FUNCTION_POSTEVENT(REMOTE_NAME, LOCAL_NAME, ...) \
500     QWEBGL_FUNCTION(REMOTE_NAME, void, LOCAL_NAME, __VA_ARGS__) { \
501         postEvent<&REMOTE_NAME>(FOR_EACH(STRIP, __VA_ARGS__)); \
502     }
503 
504 QWEBGL_FUNCTION(activeTexture, void, glActiveTexture,
505                 (GLenum) texture)
506 {
507     postEvent<&activeTexture>(texture);
508     currentContextData()->activeTextureUnit = texture;
509 }
510 
511 QWEBGL_FUNCTION_POSTEVENT(attachShader, glAttachShader,
512                           (GLuint) program, (GLuint) shader)
513 QWEBGL_FUNCTION_POSTEVENT(bindAttribLocation, glBindAttribLocation,
514                           (GLuint) program, (GLuint) index, (const GLchar *) name)
515 
516 QWEBGL_FUNCTION(bindBuffer, void, glBindBuffer,
517                 (GLenum) target, (GLuint) buffer)
518 {
519     postEvent<&bindBuffer>(target, buffer);
520     if (target == GL_ARRAY_BUFFER)
521         currentContextData()->boundArrayBuffer = buffer;
522     if (target == GL_ELEMENT_ARRAY_BUFFER)
523         currentContextData()->boundElementArrayBuffer = buffer;
524 }
525 
526 QWEBGL_FUNCTION(bindFramebuffer, void, glBindFramebuffer,
527                 (GLenum) target, (GLuint) framebuffer)
528 {
529     postEvent<&bindFramebuffer>(target, framebuffer);
530     if (target == GL_FRAMEBUFFER)
531         currentContextData()->boundDrawFramebuffer = framebuffer;
532 }
533 
534 QWEBGL_FUNCTION_POSTEVENT(bindRenderbuffer, glBindRenderbuffer,
535                           (GLenum) target, (GLuint) renderbuffer)
536 
537 QWEBGL_FUNCTION(bindTexture, void, glBindTexture,
538                 (GLenum) target, (GLuint) texture)
539 {
540     postEvent<&bindTexture>(target, texture);
541     if (target == GL_TEXTURE_2D)
542         currentContextData()->boundTexture2D = texture;
543 }
544 
545 QWEBGL_FUNCTION_POSTEVENT(blendColor, glBlendColor,
546                           (GLfloat) red, (GLfloat) green, (GLfloat) blue, (GLfloat) alpha)
547 
548 QWEBGL_FUNCTION_POSTEVENT(blendEquation, glBlendEquation,
549                           (GLenum) mode)
550 
551 QWEBGL_FUNCTION_POSTEVENT(blendEquationSeparate, glBlendEquationSeparate,
552                           (GLenum) modeRGB, (GLenum) modeAlpha)
553 
554 QWEBGL_FUNCTION_POSTEVENT(blendFunc, glBlendFunc,
555                           (GLenum) sfactor, (GLenum) dfactor)
556 
557 QWEBGL_FUNCTION_POSTEVENT(blendFuncSeparate, glBlendFuncSeparate,
558                           (GLenum) sfactorRGB, (GLenum) dfactorRGB,
559                           (GLenum) sfactorAlpha, (GLenum) dfactorAlpha)
560 
561 QWEBGL_FUNCTION(bufferData, void, glBufferData,
562                 (GLenum) target, (GLsizeiptr) size, (const void *) data, (GLenum) usage)
563 {
564     postEvent<&bufferData>(target, usage, int(size), data ? QByteArray((const char *)data, size)
565                                                           : QByteArray());
566 }
567 
568 QWEBGL_FUNCTION(bufferSubData, void, glBufferSubData,
569                 (GLenum) target, (GLintptr) offset, (GLsizeiptr) size, (const void *) data)
570 {
571     postEvent<&bufferSubData>(target, int(offset), QByteArray((const char *)data, size));
572 }
573 
574 QWEBGL_FUNCTION(checkFramebufferStatus, GLenum, glCheckFramebufferStatus,
575                 (GLenum) target)
576 {
577     return postEventAndQuery<&checkFramebufferStatus>(0u, target);
578 }
579 
580 QWEBGL_FUNCTION_POSTEVENT(clear, glClear, (GLbitfield) mask)
581 
582 QWEBGL_FUNCTION_POSTEVENT(clearColor, glClearColor,
583                           (GLfloat) red, (GLfloat) green, (GLfloat) blue, (GLfloat) alpha)
584 
585 QWEBGL_FUNCTION_POSTEVENT(clearDepthf, glClearDepthf,
586                           (GLfloat) d)
587 
588 QWEBGL_FUNCTION_POSTEVENT(clearStencil, glClearStencil,
589                           (GLint) s)
590 
591 QWEBGL_FUNCTION_POSTEVENT(colorMask, glColorMask,
592                           (GLboolean) red, (GLboolean) green, (GLboolean) blue, (GLboolean) alpha)
593 
594 QWEBGL_FUNCTION_POSTEVENT(compileShader, glCompileShader, (GLuint) shader)
595 
596 QWEBGL_FUNCTION(compressedTexImage2D, void, glCompressedTexImage2D,
597                 (GLenum) target, (GLint) level, (GLenum) internalformat,
598                 (GLsizei) width, (GLsizei) height, (GLint) border,
599                 (GLsizei) imageSize, (const void *) data) {
600     postEvent<&compressedTexImage2D>(target, level, internalformat, width, height, border,
601                                      imageSize, QByteArray(reinterpret_cast<const char *>(data),
602                                                            imageSize));
603 }
604 
605 QWEBGL_FUNCTION(compressedTexSubImage2D, void, glCompressedTexSubImage2D,
606                 (GLenum) target, (GLint) level, (GLint) xoffset, (GLint) yoffset,
607                 (GLsizei) width, (GLsizei) height, (GLenum) format,
608                 (GLsizei) imageSize, (const void *) data) {
609     postEvent<&compressedTexSubImage2D>(target, level, xoffset, yoffset, width, height, format,
610                                         imageSize, QByteArray(reinterpret_cast<const char *>(data),
611                                                               imageSize));
612 }
613 
614 QWEBGL_FUNCTION_POSTEVENT(copyTexImage2D, glCopyTexImage2D,
615                           (GLenum) target, (GLint) level, (GLenum) internalformat,
616                           (GLint) x, (GLint) y, (GLsizei) width, (GLsizei) height, (GLint) border)
617 
618 QWEBGL_FUNCTION_POSTEVENT(copyTexSubImage2D, glCopyTexSubImage2D,
619                           (GLenum) target, (GLint) level, (GLint) xoffset, (GLint) yoffset,
620                           (GLint) x, (GLint) y, (GLsizei) width, (GLsizei) height)
621 
QWEBGL_FUNCTION_NO_PARAMS(createProgram,GLuint,glCreateProgram)622 QWEBGL_FUNCTION_NO_PARAMS(createProgram, GLuint, glCreateProgram)
623 {
624     return postEventAndQuery<&createProgram>(0u);
625 }
626 
627 QWEBGL_FUNCTION(createShader, GLuint, glCreateShader,
628                 (GLenum) type)
629 {
630     return postEventAndQuery<&createShader>(0u, type);
631 }
632 
633 QWEBGL_FUNCTION_POSTEVENT(cullFace, glCullFace,
634                           (GLenum) mode)
635 
636 QWEBGL_FUNCTION(deleteBuffers, void, glDeleteBuffers,
637                 (GLsizei) n, (const GLuint *) buffers)
638 {
639     postEvent<&deleteBuffers>(n, qMakePair(buffers, n));
640     for (int i = 0; i < n; ++i) {
641         if (currentContextData()->boundArrayBuffer == buffers[i])
642             currentContextData()->boundArrayBuffer = 0;
643         if (currentContextData()->boundElementArrayBuffer == buffers[i])
644             currentContextData()->boundElementArrayBuffer = 0;
645     }
646 }
647 
648 QWEBGL_FUNCTION(deleteFramebuffers, void, glDeleteFramebuffers,
649                 (GLsizei) n, (const GLuint *) framebuffers)
650 {
651     postEvent<&deleteFramebuffers>(qMakePair(framebuffers, n));
652 }
653 
654 QWEBGL_FUNCTION_POSTEVENT(deleteProgram, glDeleteProgram,
655                           (GLuint) program)
656 
657 QWEBGL_FUNCTION(deleteRenderbuffers, void, glDeleteRenderbuffers,
658                 (GLsizei) n, (const GLuint *) renderbuffers)
659 {
660     postEvent<&deleteRenderbuffers>(qMakePair(renderbuffers, n));
661 }
662 
663 QWEBGL_FUNCTION_POSTEVENT(deleteShader, glDeleteShader,
664                           (GLuint) shader)
665 
666 QWEBGL_FUNCTION(deleteTextures, void, glDeleteTextures,
667                 (GLsizei) n, (const GLuint *) textures)
668 {
669     postEvent<&deleteTextures>(qMakePair(textures, n));
670 }
671 
672 QWEBGL_FUNCTION_POSTEVENT(depthFunc, glDepthFunc,
673                           (GLenum) func)
674 
675 QWEBGL_FUNCTION_POSTEVENT(depthMask, glDepthMask,
676                           (GLboolean) flag)
677 
678 QWEBGL_FUNCTION_POSTEVENT(depthRangef, glDepthRangef,
679                           (GLfloat) n, (GLfloat) f)
680 
681 QWEBGL_FUNCTION_POSTEVENT(detachShader, glDetachShader,
682                           (GLuint) program, (GLuint) shader)
683 
684 QWEBGL_FUNCTION(disableVertexAttribArray, void, glDisableVertexAttribArray,
685                 (GLuint) index)
686 {
687     postEvent<&disableVertexAttribArray>(index);
688     currentContextData()->vertexAttribPointers[index].enabled = false;
689 }
690 
691 QWEBGL_FUNCTION(drawArrays, void, glDrawArrays,
692                 (GLenum) mode, (GLint) first, (GLsizei) count)
693 {
694     auto event = currentContext()->createEvent(QStringLiteral("glDrawArrays"));
695     if (!event)
696         return;
697     event->addParameters(mode, first, count);
698     // Some vertex attributes may be client-side, others may not. Therefore
699     // client-side ones need to transfer the data starting from the base
700     // pointer, not just from 'first'.
701     setVertexAttribs(event, first + count);
702     QCoreApplication::postEvent(QWebGLIntegrationPrivate::instance()->webSocketServer, event);
703 }
704 
705 QWEBGL_FUNCTION(drawElements, void, glDrawElements,
706                 (GLenum) mode, (GLsizei) count, (GLenum) type, (const void *) indices)
707 {
708     auto event = currentContext()->createEvent(QStringLiteral("glDrawElements"));
709     if (!event)
710         return;
711     event->addParameters(mode, count, type);
712     setVertexAttribs(event, count);
713     ContextData *d = currentContextData();
714     if (d->boundElementArrayBuffer == 0) {
715         event->addParameters(0, QByteArray(reinterpret_cast<const char *>(indices),
716                                            count * elementSize(type)));
717     } else {
718         event->addParameters(1, uint(quintptr(indices)));
719     }
720     QCoreApplication::postEvent(QWebGLIntegrationPrivate::instance()->webSocketServer, event);
721 }
722 
723 QWEBGL_FUNCTION(enableVertexAttribArray, void, glEnableVertexAttribArray,
724                 (GLuint) index)
725 {
726     postEvent<&enableVertexAttribArray>(index);
727     currentContextData()->vertexAttribPointers[index].enabled = true;
728 }
729 
QWEBGL_FUNCTION_NO_PARAMS(finish,void,glFinish)730 QWEBGL_FUNCTION_NO_PARAMS(finish, void, glFinish)
731 {
732     postEvent<&finish>();
733 }
734 
QWEBGL_FUNCTION_NO_PARAMS(flush,void,glFlush)735 QWEBGL_FUNCTION_NO_PARAMS(flush, void, glFlush)
736 {
737     postEvent<&flush>();
738 }
739 
740 QWEBGL_FUNCTION_POSTEVENT(framebufferRenderbuffer, glFramebufferRenderbuffer,
741                           (GLenum) target, (GLenum) attachment,
742                           (GLenum) renderbuffertarget, (GLuint) renderbuffer)
743 
744 QWEBGL_FUNCTION_POSTEVENT(framebufferTexture2D, glFramebufferTexture2D,
745                           (GLenum) target, (GLenum) attachment, (GLenum) textarget,
746                           (GLuint) texture, (GLint) level)
747 
748 QWEBGL_FUNCTION_POSTEVENT(frontFace, glFrontFace,
749                           (GLenum) mode)
750 
751 QWEBGL_FUNCTION(genBuffers, void, glGenBuffers,
752                 (GLsizei) n, (GLuint *) buffers)
753 {
754     const auto values = postEventAndQuery<&genBuffers>(QVariantList(), n);
755     if (values.size() != n)
756         qCWarning(lc, "Failed to create buffers");
757     for (int i = 0; i < qMin(n, values.size()); ++i)
758         buffers[i] = values.at(i).toUInt();
759 }
760 
761 QWEBGL_FUNCTION(genFramebuffers, void, glGenFramebuffers,
762                 (GLsizei) n, (GLuint *) framebuffers)
763 {
764     const auto values = postEventAndQuery<&genFramebuffers>(QVariantList(), n);
765     if (values.size() != n)
766         qCWarning(lc, "Failed to create framebuffers");
767     for (int i = 0; i < qMin(n, values.size()); ++i)
768         framebuffers[i] = values.at(i).toUInt();
769 }
770 
771 QWEBGL_FUNCTION(genRenderbuffers, void, glGenRenderbuffers,
772                 (GLsizei) n, (GLuint *) renderbuffers)
773 {
774     const auto values = postEventAndQuery<&genRenderbuffers>(QVariantList(), n);
775     if (values.size() != n)
776         qCWarning(lc, "Failed to create render buffers");
777     for (int i = 0; i < qMin(n, values.size()); ++i)
778         renderbuffers[i] = values.at(i).toUInt();
779 }
780 
781 QWEBGL_FUNCTION(genTextures, void, glGenTextures,
782                 (GLsizei) n, (GLuint *) textures)
783 {
784     const auto values = postEventAndQuery<&genTextures>(QVariantList(), n);
785     if (values.size() != n)
786         qCWarning(lc, "Failed to create textures");
787     for (int i = 0; i < qMin(n, values.size()); ++i)
788         textures[i] = values.at(i).toUInt();
789 }
790 
791 QWEBGL_FUNCTION_POSTEVENT(generateMipmap, glGenerateMipmap,
792                           (GLenum) target)
793 
794 QWEBGL_FUNCTION(getActiveAttrib, void, glGetActiveAttrib,
795                 (GLuint) program, (GLuint) index, (GLsizei) bufSize,
796                 (GLsizei *) length, (GLint *) size, (GLenum *) type, (GLchar *) name)
797 {
798     const auto values = postEventAndQuery<&getActiveAttrib>(QVariantMap(), program, index, bufSize);
799     if (values.isEmpty())
800         return;
801     const int rtype = values["rtype"].toInt();
802     const int rsize = values["rsize"].toInt();
803     const QByteArray rname = values["rname"].toByteArray();
804     if (type)
805         *type = rtype;
806     if (size)
807         *size = rsize;
808     int len = qMax(0, qMin(bufSize - 1, rname.size()));
809     if (length)
810         *length = len;
811     if (name) {
812         memcpy(name, rname.constData(), len);
813         name[len] = '\0';
814     }
815 }
816 
817 QWEBGL_FUNCTION(getActiveUniform, void, glGetActiveUniform,
818                 (GLuint) program, (GLuint) index, (GLsizei) bufSize,
819                 (GLsizei *) length, (GLint *) size, (GLenum *) type, (GLchar *) name)
820 {
821     const auto values = postEventAndQuery<&getActiveUniform>(QVariantMap(), program, index, bufSize);
822     if (values.isEmpty())
823         return;
824     const int rtype = values["rtype"].toInt();
825     const int rsize = values["rsize"].toInt();
826     const QByteArray rname = values["rname"].toByteArray();
827     if (type)
828         *type = rtype;
829     if (size)
830         *size = rsize;
831     int len = qMax(0, qMin(bufSize - 1, rname.size()));
832     if (length)
833         *length = len;
834     if (name) {
835         memcpy(name, rname.constData(), len);
836         name[len] = '\0';
837     }
838 }
839 
840 QWEBGL_FUNCTION(getAttachedShaders, void, glGetAttachedShaders,
841                 (GLuint) program, (GLsizei) maxCount, (GLsizei *) count, (GLuint *) shaders)
842 {
843     const auto values = postEventAndQuery<&getAttachedShaders>(QVariantList(), program, maxCount);
844     *count = values.size();
845     for (int i = 0; i < values.size(); ++i)
846         shaders[i] = values.at(i).toUInt();
847 }
848 
849 QWEBGL_FUNCTION(getAttribLocation, GLint, glGetAttribLocation,
850                 (GLuint) program, (const GLchar *) name)
851 {
852     return postEventAndQuery<&getAttribLocation>(-1, program, name);
853 }
854 
855 QWEBGL_FUNCTION(getString, const GLubyte *, glGetString,
856                 (GLenum) name)
857 {
858     static QByteArrayList strings;
859     const auto it = currentContextData()->cachedParameters.find(name);
860     if (it != currentContextData()->cachedParameters.end()) {
861         auto &stringCache = currentContextData()->stringCache;
862         Q_ASSERT(it->type() == QVariant::String);
863         const auto string = it->toString().toLatin1();
864         {
865             auto it = stringCache.find(string), end = stringCache.end();
866             if (it == end)
867                 it = stringCache.insert(string);
868             return reinterpret_cast<const GLubyte *>(it->constData());
869         }
870     }
871     const auto value = postEventAndQuery<&getString>(QByteArray(), name);
872     strings.append(value);
873     return reinterpret_cast<const GLubyte *>(strings.last().constData());
874 }
875 
876 QWEBGL_FUNCTION(getIntegerv, void, glGetIntegerv,
877                 (GLenum) pname, (GLint *) data)
878 {
879     if (pname == GL_MAX_TEXTURE_SIZE) {
880         static bool ok;
881         static auto value = qgetenv("QT_WEBGL_MAX_TEXTURE_SIZE").toUInt(&ok);
882         if (ok) {
883             *data = value;
884             return;
885         }
886     }
887     const auto it = currentContextData()->cachedParameters.find(pname);
888     if (it != currentContextData()->cachedParameters.end()) {
889         QList<QVariant> values;
890         switch (it->type()) {
891         case QVariant::Map: values = it->toMap().values(); break;
892         case QVariant::List: values = it->toList(); break;
893         default: values = QVariantList{ *it };
894         }
895         for (const auto &integer : qAsConst(values)) {
896             bool ok;
897             *data = integer.toInt(&ok);
898             if (!ok)
899                 qCWarning(lc, "Failed to cast value");
900             ++data;
901         }
902         return;
903     }
904     switch (pname) {
905     case GL_CURRENT_PROGRAM:
906         *data = currentContextData()->currentProgram;
907         return;
908     case GL_FRAMEBUFFER_BINDING:
909         *data = currentContextData()->boundDrawFramebuffer;
910         return;
911     case GL_ARRAY_BUFFER_BINDING:
912         *data = currentContextData()->boundArrayBuffer;
913         return;
914     case GL_ELEMENT_ARRAY_BUFFER_BINDING:
915         *data = currentContextData()->boundElementArrayBuffer;
916         return;
917     case GL_ACTIVE_TEXTURE:
918         *data = currentContextData()->activeTextureUnit;
919         return;
920     case GL_TEXTURE_BINDING_2D:
921         *data = currentContextData()->boundTexture2D;
922         return;
923     default:
924         *data = postEventAndQuery<&getIntegerv>(0, pname);
925     }
926 }
927 
928 QWEBGL_FUNCTION(getBooleanv, void, glGetBooleanv,
929                 (GLenum) pname, (GLboolean *) data)
930 {
931     const auto it = currentContextData()->cachedParameters.find(pname);
932     if (it != currentContextData()->cachedParameters.end()) {
933         Q_ASSERT(it->type() == QVariant::Bool);
934         *data = it->toBool();
935         return;
936     }
937     *data = postEventAndQuery<&getBooleanv>(GL_FALSE, pname);
938 }
939 
940 QWEBGL_FUNCTION(enable, void, glEnable,
941                 (GLenum) cap)
942 {
943     if (!postEvent<&enable>(cap))
944         return;
945     auto it = currentContextData()->cachedParameters.find(cap);
946     if (it != currentContextData()->cachedParameters.end()) {
947         Q_ASSERT(it->type() == QVariant::Bool);
948         it->setValue(true);
949     }
950 }
951 
952 QWEBGL_FUNCTION(disable, void, glDisable,
953                 (GLenum) cap)
954 {
955     if (!postEvent<&disable>(cap))
956         return;
957     auto it = currentContextData()->cachedParameters.find(cap);
958     if (it != currentContextData()->cachedParameters.end()) {
959         Q_ASSERT(it->type() == QVariant::Bool);
960         it->setValue(false);
961     }
962 }
963 
964 QWEBGL_FUNCTION(getBufferParameteriv, void, glGetBufferParameteriv,
965                 (GLenum) target, (GLenum) pname, (GLint *) params)
966 {
967     *params = postEventAndQuery<&getBufferParameteriv>(0, target, pname);
968 }
969 
QWEBGL_FUNCTION_NO_PARAMS(getError,GLenum,glGetError)970 QWEBGL_FUNCTION_NO_PARAMS(getError, GLenum, glGetError)
971 {
972     return postEventAndQuery<&getError>(GL_NO_ERROR);
973 }
974 
975 QWEBGL_FUNCTION(getParameter, void, glGetFloatv,
976                 (GLenum) pname, (GLfloat*) data)
977 {
978     *data = postEventAndQuery<&getParameter>(0.0, pname);
979 }
980 
981 QWEBGL_FUNCTION(getFramebufferAttachmentParameteriv, void, glGetFramebufferAttachmentParameteriv,
982                 (GLenum) target, (GLenum) attachment, (GLenum) pname, (GLint *) params)
983 {
984     *params = postEventAndQuery<&getFramebufferAttachmentParameteriv>(0, target, attachment, pname);
985 }
986 
987 QWEBGL_FUNCTION(getProgramInfoLog, void, glGetProgramInfoLog,
988                 (GLuint) program, (GLsizei) bufSize, (GLsizei *) length, (GLchar *) infoLog)
989 {
990     auto value = postEventAndQuery<&getProgramInfoLog>(QString(), program);
991     *length = value.length();
992     if (bufSize >= value.length())
993         std::memcpy(infoLog, value.constData(), value.length());
994 }
995 
996 QWEBGL_FUNCTION(getProgramiv, void, glGetProgramiv,
997                 (GLuint) program, (GLenum) pname, (GLint *) params)
998 {
999     *params = postEventAndQuery<&getProgramiv>(0, program, pname);
1000 }
1001 
1002 QWEBGL_FUNCTION(getRenderbufferParameteriv, void, glGetRenderbufferParameteriv,
1003                 (GLenum) target, (GLenum) pname, (GLint *) params)
1004 {
1005     *params = postEventAndQuery<&getRenderbufferParameteriv>(0, target, pname);
1006 }
1007 
1008 QWEBGL_FUNCTION(getShaderInfoLog, void, glGetShaderInfoLog,
1009                 (GLuint) shader, (GLsizei) bufSize, (GLsizei *) length, (GLchar *) infoLog)
1010 {
1011     const auto value = postEventAndQuery<&getShaderInfoLog>(QString(), shader);
1012     *length = value.length();
1013     if (bufSize >= value.length())
1014         std::memcpy(infoLog, value.constData(), value.length());
1015 }
1016 
1017 QWEBGL_FUNCTION(getShaderPrecisionFormat, void, glGetShaderPrecisionFormat,
1018                 (GLenum) shadertype, (GLenum) precisiontype, (GLint *) range, (GLint *) precision)
1019 {
1020     const auto value = postEventAndQuery<&getShaderPrecisionFormat>(QVariantMap(), shadertype,
1021                                                                    precisiontype);
1022     bool ok;
1023     range[0] = value[QStringLiteral("rangeMin")].toInt(&ok);
1024     if (!ok)
1025         qCCritical(lc, "Invalid rangeMin value");
1026     range[1] = value[QStringLiteral("rangeMax")].toInt(&ok);
1027     if (!ok)
1028         qCCritical(lc, "Invalid rangeMax value");
1029     *precision = value[QStringLiteral("precision")].toInt(&ok);
1030     if (!ok)
1031         qCCritical(lc, "Invalid precision value");
1032 }
1033 
1034 QWEBGL_FUNCTION(getShaderSource, void, glGetShaderSource,
1035                 (GLuint) shader, (GLsizei) bufSize, (GLsizei *) length, (GLchar *) source)
1036 {
1037     const auto value = postEventAndQuery<&getShaderSource>(QString(), shader);
1038     *length = value.length();
1039     if (bufSize >= value.length())
1040         std::memcpy(source, value.constData(), value.length());
1041 }
1042 
1043 QWEBGL_FUNCTION(getShaderiv, void, glGetShaderiv,
1044                 (GLuint) shader, (GLenum) pname, (GLint *) params)
1045 {
1046     if (pname == GL_INFO_LOG_LENGTH) {
1047         GLsizei bufSize = 0;
1048         glGetShaderInfoLog(shader, bufSize, &bufSize, nullptr);
1049         *params = bufSize;
1050         return;
1051     }
1052     if (pname == GL_SHADER_SOURCE_LENGTH) {
1053         GLsizei bufSize = 0;
1054         glGetShaderSource(shader, bufSize, &bufSize, nullptr);
1055         *params = bufSize;
1056         return;
1057     }
1058     *params = postEventAndQuery<&getShaderiv>(0, shader, pname);
1059 }
1060 
1061 QWEBGL_FUNCTION(getTexParameterfv, void, glGetTexParameterfv,
1062                 (GLenum) target, (GLenum) pname, (GLfloat *) params)
1063 {
1064     *params = postEventAndQuery<&getTexParameterfv>(0.f, target, pname);
1065 }
1066 
1067 QWEBGL_FUNCTION(getTexParameteriv, void, glGetTexParameteriv,
1068                 (GLenum) target, (GLenum) pname, (GLint *) params)
1069 {
1070     *params = postEventAndQuery<&getTexParameteriv>(0, target, pname);
1071 }
1072 
1073 QWEBGL_FUNCTION(getUniformLocation, GLint, glGetUniformLocation,
1074                 (GLuint) program, (const GLchar *) name)
1075 {
1076     return postEventAndQuery<&getUniformLocation>(-1, program, name);
1077 }
1078 
1079 QWEBGL_FUNCTION(getUniformfv, void, glGetUniformfv,
1080                 (GLuint) program, (GLint) location, (GLfloat *) params)
1081 {
1082     *params = postEventAndQuery<&getUniformfv>(0.f, program, location);
1083 }
1084 
1085 QWEBGL_FUNCTION(getUniformiv, void, glGetUniformiv,
1086                 (GLuint) program, (GLint) location, (GLint *) params)
1087 {
1088     *params = postEventAndQuery<&getUniformiv>(0, program, location);
1089 }
1090 
1091 QWEBGL_FUNCTION(getVertexAttribPointerv, void, glGetVertexAttribPointerv,
1092                 (GLuint) index, (GLenum) pname, (void **) pointer)
1093 {
1094     Q_UNUSED(index);
1095     Q_UNUSED(pname);
1096     Q_UNUSED(pointer);
1097     qFatal("glGetVertexAttribPointerv not supported");
1098     return;
1099 }
1100 
1101 QWEBGL_FUNCTION(getVertexAttribfv, void, glGetVertexAttribfv,
1102                 (GLuint) index, (GLenum) pname, (GLfloat *) params)
1103 {
1104     *params = postEventAndQuery<&getVertexAttribfv>(0.f, index, pname);
1105 }
1106 
1107 QWEBGL_FUNCTION(getVertexAttribiv, void, glGetVertexAttribiv,
1108                 (GLuint) index, (GLenum) pname, (GLint *) params)
1109 {
1110     *params = postEventAndQuery<&getVertexAttribiv>(0, index, pname);
1111 }
1112 
1113 QWEBGL_FUNCTION_POSTEVENT(hint, glHint,
1114                           (GLenum) target, (GLenum) mode)
1115 
1116 QWEBGL_FUNCTION(isBuffer, GLboolean, glIsBuffer,
1117                 (GLuint) buffer)
1118 {
1119     return postEventAndQuery<&isBuffer>(GL_FALSE, buffer);
1120 }
1121 
1122 QWEBGL_FUNCTION(isEnabled, GLboolean, glIsEnabled,
1123                 (GLenum) cap)
1124 {
1125     return postEventAndQuery<&isEnabled>(GL_FALSE, cap);
1126 }
1127 
1128 QWEBGL_FUNCTION(isFramebuffer, GLboolean, glIsFramebuffer,
1129                 (GLuint) framebuffer)
1130 {
1131     return postEventAndQuery<&isFramebuffer>(GL_FALSE, framebuffer);
1132 }
1133 
1134 QWEBGL_FUNCTION(isProgram, GLboolean, glIsProgram,
1135                 (GLuint) program)
1136 {
1137     return postEventAndQuery<&isProgram>(GL_FALSE, program);
1138 }
1139 
1140 QWEBGL_FUNCTION(isRenderbuffer, GLboolean, glIsRenderbuffer,
1141                 (GLuint) renderbuffer)
1142 {
1143     return postEventAndQuery<&isRenderbuffer>(GL_FALSE, renderbuffer);
1144 }
1145 
1146 QWEBGL_FUNCTION(isShader, GLboolean, glIsShader,
1147                 (GLuint) shader)
1148 {
1149     return postEventAndQuery<&isShader>(GL_FALSE, shader);
1150 }
1151 
1152 QWEBGL_FUNCTION(isTexture, GLboolean, glIsTexture,
1153                 (GLuint) texture)
1154 {
1155     return postEventAndQuery<&isTexture>(GL_FALSE, texture);
1156 }
1157 
1158 QWEBGL_FUNCTION_POSTEVENT(lineWidth, glLineWidth,
1159                           (GLfloat) width)
1160 
1161 QWEBGL_FUNCTION_POSTEVENT(linkProgram, glLinkProgram,
1162                           (GLuint) program)
1163 
1164 QWEBGL_FUNCTION(pixelStorei, void, glPixelStorei,
1165                 (GLenum) pname, (GLint) param)
1166 {
1167     postEvent<&pixelStorei>(pname, param);
1168     switch (pname) {
1169     case GL_UNPACK_ALIGNMENT: currentContextData()->unpackAlignment = param; break;
1170     }
1171 }
1172 
1173 QWEBGL_FUNCTION_POSTEVENT(polygonOffset, glPolygonOffset,
1174                           (GLfloat) factor, (GLfloat) units)
1175 
1176 QWEBGL_FUNCTION(readPixels, void, glReadPixels,
1177                 (GLint) x, (GLint) y, (GLsizei) width, (GLsizei) height,
1178                 (GLenum) format, (GLenum) type, (void *) pixels)
1179 {
1180     const auto value = postEventAndQuery<&readPixels>(QByteArray(), x, y, width, height, format,
1181                                                      type);
1182     if (!value.isEmpty())
1183         std::memcpy(pixels, value.constData(), value.size());
1184 }
1185 
QWEBGL_FUNCTION_NO_PARAMS(releaseShaderCompiler,void,glReleaseShaderCompiler)1186 QWEBGL_FUNCTION_NO_PARAMS(releaseShaderCompiler, void, glReleaseShaderCompiler)
1187 {
1188     postEvent<&releaseShaderCompiler>();
1189 }
1190 
1191 QWEBGL_FUNCTION_POSTEVENT(renderbufferStorage, glRenderbufferStorage,
1192                           (GLenum) target, (GLenum) internalformat,
1193                           (GLsizei) width, (GLsizei) height)
1194 
1195 QWEBGL_FUNCTION_POSTEVENT(sampleCoverage, glSampleCoverage,
1196                           (GLfloat) value, (GLboolean) invert)
1197 
1198 QWEBGL_FUNCTION_POSTEVENT(scissor, glScissor,
1199                           (GLint) x, (GLint) y, (GLsizei) width, (GLsizei) height)
1200 
1201 QWEBGL_FUNCTION(shaderBinary, void, glShaderBinary,
1202                 (GLsizei), (const GLuint *), (GLenum), (const void *), (GLsizei))
1203 {
1204     qFatal("WebGL does not allow precompiled shaders");
1205 }
1206 
1207 QWEBGL_FUNCTION(shaderSource, void, glShaderSource,
1208                 (GLuint) shader, (GLsizei) count,
1209                 (const GLchar *const *) string, (const GLint *) length)
1210 {
1211     QString fullString;
1212     std::function<void(int)> concat;
1213     if (length)
__anon10c88bc80202(int i) 1214         concat = [&](int i) { fullString.append(QString::fromLatin1(string[i], length[i])); };
1215     else
__anon10c88bc80302(int i) 1216         concat = [&](int i) { fullString.append(QString::fromLatin1(string[i])); };
1217     for (int i = 0; i < count; ++i)
1218         concat(i);
1219     postEvent<&shaderSource>(shader, fullString);
1220 }
1221 
1222 QWEBGL_FUNCTION_POSTEVENT(stencilFunc, glStencilFunc,
1223                           (GLenum) func, (GLint) ref, (GLuint) mask)
1224 
1225 QWEBGL_FUNCTION_POSTEVENT(stencilFuncSeparate, glStencilFuncSeparate,
1226                           (GLenum) face, (GLenum) func, (GLint) ref, (GLuint) mask)
1227 
1228 QWEBGL_FUNCTION_POSTEVENT(stencilMask, glStencilMask,
1229                           (GLuint) mask)
1230 
1231 QWEBGL_FUNCTION_POSTEVENT(stencilMaskSeparate, glStencilMaskSeparate,
1232                           (GLenum) face, (GLuint) mask)
1233 
1234 QWEBGL_FUNCTION_POSTEVENT(stencilOp, glStencilOp,
1235                           (GLenum) fail, (GLenum) zfail, (GLenum) zpass)
1236 
1237 QWEBGL_FUNCTION_POSTEVENT(stencilOpSeparate, glStencilOpSeparate,
1238                           (GLenum) face, (GLenum) sfail, (GLenum) dpfail, (GLenum) dppass)
1239 
1240 QWEBGL_FUNCTION(texImage2D, void,  glTexImage2D,
1241                 (GLenum) target, (GLint) level, (GLint) internalformat,
1242                 (GLsizei) width, (GLsizei) height, (GLint) border, (GLenum) format, (GLenum) type,
1243                 (const void *) pixels)
1244 {
1245     const auto data = reinterpret_cast<const char *>(pixels);
1246     const auto dataSize = imageSize(width, height, format, type,
1247                                     currentContextData()->pixelStorage);
__anon10c88bc80402(const char *pointer, int size) 1248     const bool isNull = data == nullptr || [](const char *pointer, int size) {
1249         const char *const end = pointer + size;
1250         const unsigned int zero = 0u;
1251         const char *const late = end + 1 - sizeof(zero);
1252         while (pointer < late) { // we have at least sizeof(zero) more bytes to check:
1253             if (*reinterpret_cast<const unsigned int *>(pointer) != zero)
1254                 return false;
1255             pointer += sizeof(zero);
1256         }
1257         return pointer >= end || std::memcmp(pointer, &zero, end - pointer) == 0;
1258     }(data, dataSize);
1259     postEvent<&texImage2D>(target, level, internalformat, width, height, border, format, type,
1260                            isNull ? nullptr : QByteArray(data, dataSize));
1261 }
1262 
1263 QWEBGL_FUNCTION_POSTEVENT(texParameterf, glTexParameterf,
1264                           (GLenum) target, (GLenum) pname, (GLfloat) param)
1265 
1266 QWEBGL_FUNCTION(texParameterfv, void, glTexParameterfv,
1267                 (GLenum), (GLenum), (const GLfloat *))
1268 {
1269     qFatal("glTexParameterfv not implemented");
1270 }
1271 
1272 QWEBGL_FUNCTION_POSTEVENT(texParameteri, glTexParameteri,
1273                           (GLenum) target, (GLenum) pname, (GLint) param)
1274 
1275 QWEBGL_FUNCTION(texParameteriv, void, glTexParameteriv,
1276                 (GLenum), (GLenum), (const GLint *))
1277 {
1278     qFatal("glTexParameteriv not implemented");
1279 }
1280 
1281 QWEBGL_FUNCTION(texSubImage2D, void, glTexSubImage2D,
1282                 (GLenum) target, (GLint) level, (GLint) xoffset, (GLint) yoffset,
1283                 (GLsizei) width, (GLsizei) height, (GLenum) format, (GLenum) type,
1284                 (const void *) pixels)
1285 {
1286     postEvent<&texSubImage2D>(target, level, xoffset, yoffset, width, height, format, type,
1287                              pixels ? QByteArray(reinterpret_cast<const char *>(pixels),
1288                                                  imageSize(width, height, format, type,
1289                                                            currentContextData()->pixelStorage))
1290                                     : nullptr);
1291 }
1292 
1293 QWEBGL_FUNCTION_POSTEVENT(uniform1f, glUniform1f, (GLint) location, (GLfloat) v0)
1294 
1295 QWEBGL_FUNCTION(uniform1fv, void, glUniform1fv,
1296                 (GLint) location, (GLsizei) count, (const GLfloat *) value)
1297 {
1298     postEvent<&uniform1fv>(location, qMakePair(value, count));
1299 }
1300 
1301 QWEBGL_FUNCTION_POSTEVENT(uniform1i, glUniform1i,
1302                           (GLint) location, (GLint) v0)
1303 
1304 QWEBGL_FUNCTION(uniform1iv, void, glUniform1iv,
1305                 (GLint) location, (GLsizei) count, (const GLint *) value)
1306 {
1307     postEvent<&uniform1iv>(location, qMakePair(value, count));
1308 }
1309 
1310 QWEBGL_FUNCTION_POSTEVENT(uniform2f, glUniform2f,
1311                           (GLint) location, (GLfloat) v0, (GLfloat) v1)
1312 
1313 QWEBGL_FUNCTION(uniform2fv, void, glUniform2fv,
1314                 (GLint) location, (GLsizei) count, (const GLfloat *) value)
1315 {
1316     postEvent<&uniform2fv>(location, qMakePair(value, count * 2));
1317 }
1318 
1319 QWEBGL_FUNCTION_POSTEVENT(uniform2i, glUniform2i,
1320                           (GLint) location, (GLint) v0, (GLint) v1)
1321 
1322 QWEBGL_FUNCTION(uniform2iv, void, glUniform2iv,
1323                 (GLint) location, (GLsizei) count, (const GLint *) value)
1324 {
1325     postEvent<&uniform2iv>(location, qMakePair(value, count * 2));
1326 }
1327 
1328 QWEBGL_FUNCTION_POSTEVENT(uniform3f, glUniform3f,
1329                           (GLint) location, (GLfloat) v0, (GLfloat) v1, (GLfloat) v2)
1330 
1331 QWEBGL_FUNCTION(uniform3fv, void, glUniform3fv,
1332                 (GLint) location, (GLsizei) count, (const GLfloat *) value)
1333 {
1334     postEvent<&uniform3fv>(location, qMakePair(value, count * 3));
1335 }
1336 
1337 QWEBGL_FUNCTION_POSTEVENT(uniform3i, glUniform3i,
1338                           (GLint) location, (GLint) v0, (GLint) v1, (GLint) v2)
1339 
1340 QWEBGL_FUNCTION(uniform3iv, void, glUniform3iv,
1341                 (GLint) location, (GLsizei) count, (const GLint *) value)
1342 {
1343     postEvent<&uniform3iv>(location, qMakePair(value, count * 3));
1344 }
1345 
1346 QWEBGL_FUNCTION_POSTEVENT(uniform4f, glUniform4f,
1347                           (GLint) location, (GLfloat) v0, (GLfloat) v1,
1348                           (GLfloat) v2, (GLfloat) v3)
1349 
1350 QWEBGL_FUNCTION(uniform4fv, void, glUniform4fv,
1351                 (GLint) location, (GLsizei) count, (const GLfloat *) value)
1352 {
1353     postEvent<&uniform4fv>(location, qMakePair(value, count * 4));
1354 }
1355 
1356 QWEBGL_FUNCTION_POSTEVENT(uniform4i, glUniform4i,
1357                           (GLint) location, (GLint) v0, (GLint) v1, (GLint) v2, (GLint) v3)
1358 
1359 QWEBGL_FUNCTION(uniform4iv, void, glUniform4iv,
1360                 (GLint) location, (GLsizei) count, (const GLint *) value)
1361 {
1362     postEvent<&uniform4iv>(location, qMakePair(value, count * 4));
1363 }
1364 
1365 QWEBGL_FUNCTION(uniformMatrix2fv, void, glUniformMatrix2fv,
1366                 (GLint) location, (GLsizei) count, (GLboolean) transpose, (const GLfloat *) value)
1367 {
1368     postEvent<&uniformMatrix2fv>(location, transpose, qMakePair(value, count * 4));
1369 }
1370 
1371 QWEBGL_FUNCTION(uniformMatrix3fv, void, glUniformMatrix3fv,
1372                 (GLint) location, (GLsizei) count, (GLboolean) transpose, (const GLfloat *) value)
1373 {
1374     postEvent<&uniformMatrix3fv>(location, transpose, qMakePair(value, count * 9));
1375 }
1376 
1377 QWEBGL_FUNCTION(uniformMatrix4fv, void, glUniformMatrix4fv,
1378                 (GLint) location, (GLsizei) count, (GLboolean) transpose, (const GLfloat *) value)
1379 {
1380     postEvent<&uniformMatrix4fv>(location, transpose, qMakePair(value, count * 16));
1381 }
1382 
1383 QWEBGL_FUNCTION_POSTEVENT(useProgram, glUseProgram,
1384                           (GLuint) program)
1385 
1386 QWEBGL_FUNCTION_POSTEVENT(validateProgram, glValidateProgram,
1387                           (GLuint) program)
1388 
1389 QWEBGL_FUNCTION_POSTEVENT(vertexAttrib1f, glVertexAttrib1f,
1390                           (GLuint) index, (GLfloat) x)
1391 
1392 QWEBGL_FUNCTION(vertexAttrib1fv, void, glVertexAttrib1fv,
1393                 (GLuint) index, (const GLfloat *) v)
1394 {
1395     postEvent<&vertexAttrib1fv>(index, v[0]);
1396 }
1397 
1398 QWEBGL_FUNCTION_POSTEVENT(vertexAttrib2f, glVertexAttrib2f,
1399                           (GLuint) index, (GLfloat) x, (GLfloat) y)
1400 
1401 QWEBGL_FUNCTION(vertexAttrib2fv, void, glVertexAttrib2fv,
1402                 (GLuint) index, (const GLfloat *) v)
1403 {
1404     postEvent<&vertexAttrib2fv>(index, v[0], v[1]);
1405 }
1406 
1407 QWEBGL_FUNCTION_POSTEVENT(vertexAttrib3f, glVertexAttrib3f,
1408                           (GLuint) index, (GLfloat) x, (GLfloat) y, (GLfloat) z)
1409 
1410 QWEBGL_FUNCTION(vertexAttrib3fv, void, glVertexAttrib3fv,
1411                 (GLuint) index, (const GLfloat *) v)
1412 {
1413     postEvent<&vertexAttrib3fv>(index, v[0], v[1], v[2]);
1414 }
1415 
1416 QWEBGL_FUNCTION_POSTEVENT(vertexAttrib4f, glVertexAttrib4f,
1417                           (GLuint) index, (GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w)
1418 
1419 QWEBGL_FUNCTION(vertexAttrib4fv, void, glVertexAttrib4fv,
1420                 (GLuint) index, (const GLfloat *) v)
1421 {
1422     postEvent<&vertexAttrib4fv>(index, v[0], v[1], v[2], v[3]);
1423 }
1424 
1425 QWEBGL_FUNCTION(vertexAttribPointer, void, glVertexAttribPointer,
1426                 (GLuint) index, (GLint) size, (GLenum) type,
1427                 (GLboolean) normalized, (GLsizei) stride, (const void *) pointer)
1428 {
1429     ContextData *d = currentContextData();
1430     ContextData::VertexAttrib &va(d->vertexAttribPointers[index]);
1431     va.arrayBufferBinding = d->boundArrayBuffer;
1432     va.size = size;
1433     va.type = type;
1434     va.normalized = normalized;
1435     va.stride = stride;
1436     va.pointer = pointer;
1437     if (d->boundArrayBuffer)
1438         postEvent<&vertexAttribPointer>(index, size, type, normalized, stride,
1439                                        uint(quintptr(pointer)));
1440 }
1441 
1442 QWEBGL_FUNCTION(viewport, void, glViewport,
1443                 (GLint) x, (GLint) y, (GLsizei) width, (GLsizei) height)
1444 {
1445     postEvent<&viewport>(x, y, width, height);
1446     auto it = currentContextData()->cachedParameters.find(GL_VIEWPORT);
1447     if (it != currentContextData()->cachedParameters.end())
1448         it->setValue(QVariantList{ x, y, width, height });
1449 }
1450 
1451 QWEBGL_FUNCTION_POSTEVENT(blitFramebufferEXT, glBlitFramebufferEXT,
1452                           (GLint) srcX0, (GLint) srcY0, (GLint) srcX1, (GLint) srcY1,
1453                           (GLint) dstX0, (GLint) dstY0, (GLint) dstX1, (GLint) dstY1,
1454                           (GLbitfield) mask, (GLenum) filter)
1455 
1456 QWEBGL_FUNCTION_POSTEVENT(renderbufferStorageMultisampleEXT, glRenderbufferStorageMultisampleEXT,
1457                 (GLenum) target, (GLsizei) samples, (GLenum) internalformat, (GLsizei) width,
1458                 (GLsizei) height)
1459 
1460 QWEBGL_FUNCTION(getTexLevelParameteriv, void, glGetTexLevelParameteriv,
1461                 (GLenum), (GLint), (GLenum), (GLint *))
1462 {
1463     qFatal("glGetTexLevelParameteriv not supported");
1464 }
1465 
1466 #undef QWEBGL_FUNCTION
1467 
1468 extern const GLFunction makeCurrent("makeCurrent");
1469 extern const GLFunction swapBuffers("swapBuffers");
1470 
1471 }
1472 
QWebGLContext(const QSurfaceFormat & format)1473 QWebGLContext::QWebGLContext(const QSurfaceFormat &format) :
1474     d_ptr(new QWebGLContextPrivate)
1475 {
1476     Q_D(QWebGLContext);
1477     d->id = d->nextId.fetchAndAddOrdered(1);
1478     qCDebug(lc, "Creating context %d", d->id);
1479     d->surfaceFormat = format;
1480     d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
1481 }
1482 
~QWebGLContext()1483 QWebGLContext::~QWebGLContext()
1484 {}
1485 
format() const1486 QSurfaceFormat QWebGLContext::format() const
1487 {
1488     Q_D(const QWebGLContext);
1489     return d->surfaceFormat;
1490 }
1491 
swapBuffers(QPlatformSurface * surface)1492 void QWebGLContext::swapBuffers(QPlatformSurface *surface)
1493 {
1494     Q_UNUSED(surface);
1495     auto event = createEvent(QStringLiteral("swapBuffers"), true);
1496     if (!event)
1497         return;
1498     lockMutex();
1499     QCoreApplication::postEvent(QWebGLIntegrationPrivate::instance()->webSocketServer, event);
1500     waitCondition(1000);
1501     unlockMutex();
1502 }
1503 
makeCurrent(QPlatformSurface * surface)1504 bool QWebGLContext::makeCurrent(QPlatformSurface *surface)
1505 {
1506     Q_D(QWebGLContext);
1507 
1508     qCDebug(lc, "%p", surface);
1509     if (surface->surface()->surfaceClass() == QSurface::Window) {
1510         const auto window = static_cast<QWebGLWindow *>(surface);
1511         if (window->winId() == WId(-1))
1512             return false;
1513     }
1514 
1515     QOpenGLContextPrivate::setCurrentContext(context());
1516     d->currentSurface = surface;
1517 
1518     auto event = createEvent(QStringLiteral("makeCurrent"));
1519     if (!event)
1520         return false;
1521     event->addInt(d->id);
1522     if (surface->surface()->surfaceClass() == QSurface::Window) {
1523         auto window = static_cast<QWebGLWindow *>(surface);
1524         if (s_contextData[id()].cachedParameters.isEmpty()) {
1525             auto future = window->d_func()->defaults.get_future();
1526             std::future_status status = std::future_status::timeout;
1527             while (status == std::future_status::timeout) {
1528                 if (!QWebGLIntegrationPrivate::instance()->findClientData(surface))
1529                     return false;
1530                 status = future.wait_for(std::chrono::milliseconds(100));
1531             }
1532             s_contextData[id()].cachedParameters  = future.get();
1533         }
1534         event->addInt(window->window()->width());
1535         event->addInt(window->window()->height());
1536         event->addInt(window->winId());
1537     } else if (surface->surface()->surfaceClass() == QSurface::Offscreen) {
1538         qCDebug(lc, "QWebGLContext::makeCurrent: QSurface::Offscreen not implemented");
1539     }
1540     QCoreApplication::postEvent(QWebGLIntegrationPrivate::instance()->webSocketServer, event);
1541     return true;
1542 }
1543 
doneCurrent()1544 void QWebGLContext::doneCurrent()
1545 {
1546     postEvent<&QWebGL::makeCurrent>(0, 0, 0, 0);
1547 }
1548 
isValid() const1549 bool QWebGLContext::isValid() const
1550 {
1551     Q_D(const QWebGLContext);
1552     return d->id != -1;
1553 }
1554 
getProcAddress(const char * procName)1555 QFunctionPointer QWebGLContext::getProcAddress(const char *procName)
1556 {
1557     const auto it = GLFunction::byName.find(procName);
1558     return it != GLFunction::byName.end() ? (*it)->functionPointer : nullptr;
1559 }
1560 
id() const1561 int QWebGLContext::id() const
1562 {
1563     Q_D(const QWebGLContext);
1564     return d->id;
1565 }
1566 
currentSurface() const1567 QPlatformSurface *QWebGLContext::currentSurface() const
1568 {
1569     Q_D(const QWebGLContext);
1570     return d->currentSurface;
1571 }
1572 
createEvent(const QString & functionName,bool wait)1573 QWebGLFunctionCall *QWebGLContext::createEvent(const QString &functionName, bool wait)
1574 {
1575     auto context = QOpenGLContext::currentContext();
1576     Q_ASSERT(context);
1577     const auto handle = static_cast<QWebGLContext *>(context->handle());
1578     if (!handle)
1579         return nullptr;
1580     auto integrationPrivate = QWebGLIntegrationPrivate::instance();
1581     const auto clientData = integrationPrivate->findClientData(handle->currentSurface());
1582     if (!clientData || !clientData->socket
1583             || clientData->socket->state() != QAbstractSocket::ConnectedState)
1584         return nullptr;
1585     const auto pointer = new QWebGLFunctionCall(functionName, handle->currentSurface(), wait);
1586     if (wait)
1587         QWebGLContextPrivate::waitingIds.insert(pointer->id());
1588 
1589     return pointer;
1590 }
1591 
queryValue(int id)1592 QVariant QWebGLContext::queryValue(int id)
1593 {
1594     if (!QWebGLContextPrivate::waitingIds.contains(id)) {
1595         qCWarning(lc, "Unexpected id (%d)", id);
1596         return QVariant();
1597     }
1598 
1599     static auto queryValue = [](int id)
1600     {
1601         lockMutex();
1602         waitCondition(10);
1603         unlockMutex();
1604         return QWebGLIntegrationPrivate::instance()->webSocketServer->queryValue(id);
1605     };
1606 
1607     const auto handle = static_cast<QWebGLContext *>(currentContext()->context()->handle());
1608     QVariant variant = queryValue(id);
1609     while (variant.isNull()) {
1610         auto integrationPrivate = QWebGLIntegrationPrivate::instance();
1611         const auto clientData = integrationPrivate->findClientData(handle->currentSurface());
1612         if (!clientData || !clientData->socket
1613                 || clientData->socket->state() != QAbstractSocket::ConnectedState)
1614             return QVariant();
1615         variant = queryValue(id);
1616     }
1617     QWebGLContextPrivate::waitingIds.remove(id);
1618     return variant;
1619 }
1620 
supportedFunctions()1621 QStringList QWebGLContext::supportedFunctions()
1622 {
1623     return GLFunction::remoteFunctionNames;
1624 }
1625 
functionIndex(const QString & functionName)1626 quint8 QWebGLContext::functionIndex(const QString &functionName)
1627 {
1628     const auto it = GLFunction::byName.find(functionName);
1629     Q_ASSERT(it != GLFunction::byName.end());
1630     return (*it)->id;
1631 }
1632 
1633 QT_END_NAMESPACE
1634