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