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 | { |
73 | 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 { |
87 | 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 | |
105 | QWebGLContext *currentContext() |
106 | { |
107 | auto context = QOpenGLContext::currentContext(); |
108 | if (context) |
109 | return static_cast<QWebGLContext *>(context->handle()); |
110 | return nullptr; |
111 | } |
112 | |
113 | ContextData *currentContextData() |
114 | { |
115 | auto context = currentContext(); |
116 | if (context) |
117 | return &s_contextData[context->id()]; |
118 | return nullptr; |
119 | } |
120 | |
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, .bytesPerPixel: 4 }, |
132 | { GL_RGBA, GL_BYTE, .bytesPerPixel: 4 }, |
133 | { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, .bytesPerPixel: 2 }, |
134 | { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, .bytesPerPixel: 2 }, |
135 | { GL_RGBA, GL_FLOAT, .bytesPerPixel: 16 }, |
136 | { GL_RGB, GL_UNSIGNED_BYTE, .bytesPerPixel: 3 }, |
137 | { GL_RGB, GL_BYTE, .bytesPerPixel: 3 }, |
138 | { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, .bytesPerPixel: 2 }, |
139 | { GL_RGB, GL_FLOAT, .bytesPerPixel: 12 }, |
140 | |
141 | { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, .bytesPerPixel: 2 }, |
142 | { GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, .bytesPerPixel: 4 }, |
143 | { GL_DEPTH_COMPONENT, GL_FLOAT, .bytesPerPixel: 4 }, |
144 | |
145 | { GL_RGBA, GL_UNSIGNED_BYTE, .bytesPerPixel: 4 }, |
146 | { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, .bytesPerPixel: 2 }, |
147 | { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, .bytesPerPixel: 2 }, |
148 | { GL_RGB, GL_UNSIGNED_BYTE, .bytesPerPixel: 3 }, |
149 | { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, .bytesPerPixel: 2 }, |
150 | { GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, .bytesPerPixel: 2 }, |
151 | { GL_LUMINANCE, GL_UNSIGNED_BYTE, .bytesPerPixel: 1 }, |
152 | { GL_ALPHA, GL_UNSIGNED_BYTE, .bytesPerPixel: 1 }, |
153 | |
154 | { GL_BGRA_EXT, GL_UNSIGNED_BYTE, .bytesPerPixel: 4 }, |
155 | { GL_BGRA_EXT, GL_BYTE, .bytesPerPixel: 4 }, |
156 | { GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4, .bytesPerPixel: 2 }, |
157 | { GL_BGRA_EXT, GL_UNSIGNED_SHORT_5_5_5_1, .bytesPerPixel: 2 }, |
158 | { GL_BGRA_EXT, GL_FLOAT, .bytesPerPixel: 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 | |
176 | static void lockMutex() |
177 | { |
178 | QWebGLIntegrationPrivate::instance()->webSocketServer->mutex()->lock(); |
179 | } |
180 | |
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(lockedMutex: mutex, time); |
186 | } |
187 | |
188 | static void unlockMutex() |
189 | { |
190 | auto mutex = QWebGLIntegrationPrivate::instance()->webSocketServer->mutex(); |
191 | mutex->unlock(); |
192 | } |
193 | |
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 | |
210 | static int vertexSize(GLint elementsPerVertex, GLenum type) |
211 | { |
212 | return elementSize(type) * elementsPerVertex; |
213 | } |
214 | |
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(elementsPerVertex: elemsPerVertex, type); |
221 | |
222 | if (stride == 0) |
223 | stride = vsize; |
224 | |
225 | return vsize + (count - 1) * stride; |
226 | } |
227 | |
228 | static void setVertexAttribs(QWebGLFunctionCall *event, GLsizei count) |
229 | { |
230 | event->addInt(value: 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, elemsPerVertex: va.size, type: va.type, stride: va.stride); |
236 | event->addParameters(arguments: it.key(), arguments: va.size, arguments: int(va.type), arguments: va.normalized, arguments: va.stride); |
237 | // found an enabled vertex attribute that was specified with a client-side pointer |
238 | event->addData(data: QByteArray(reinterpret_cast<const char *>(va.pointer), len)); |
239 | } |
240 | } |
241 | } |
242 | |
243 | template<class POINTER, class COUNT> |
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> |
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> |
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> |
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> |
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 { |
296 | static int typeId() { return qMetaTypeId<T>(); } |
297 | static bool isArray() { return std::is_pointer<T>(); } |
298 | }; |
299 | |
300 | template<typename T> |
301 | struct ParameterTypeTraits<T*> : ParameterTypeTraits<T> { |
302 | 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 { |
316 | Parameter() {} |
317 | 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 | |
330 | 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(akey: localName, avalue: this); |
339 | id = remoteFunctionNames.size(); |
340 | Q_ASSERT(remoteFunctionNames.size() <= std::numeric_limits<quint8>::max()); |
341 | remoteFunctionNames.append(t: remoteName); |
342 | Q_ASSERT(byName.size() == remoteFunctionNames.size()); |
343 | } |
344 | |
345 | 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> |
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(surface: 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 | |
371 | static void postEventImpl(QWebGLFunctionCall *event) |
372 | { |
373 | if (event->isBlocking()) |
374 | QWebGLContextPrivate::waitingIds.insert(value: event->id()); |
375 | QCoreApplication::postEvent(receiver: QWebGLIntegrationPrivate::instance()->webSocketServer, event); |
376 | } |
377 | |
378 | template<const GLFunction *Function, class... Ts> |
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> |
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> |
404 | inline int postEventImpl(bool wait, Ts&&... arguments) |
405 | { |
406 | return createEventAndPostImpl<Function>(wait, arguments...); |
407 | } |
408 | |
409 | template<const GLFunction *Function> |
410 | inline int postEvent(bool wait) |
411 | { |
412 | return createEventAndPostImpl<Function>(wait); |
413 | } |
414 | |
415 | template<const GLFunction *Function, class...Ts> |
416 | inline int postEvent(Ts&&... arguments) |
417 | { |
418 | return postEventImpl<Function>(false, arguments...); |
419 | } |
420 | |
421 | template<const GLFunction *Function, class ReturnType, class...Ts> |
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>(arguments&: 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>(arguments&: target, arguments&: 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>(arguments&: target, arguments&: 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>(arguments&: target, arguments&: 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>(arguments&: target, arguments&: usage, arguments: int(size), arguments: 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>(arguments&: target, arguments: int(offset), arguments: QByteArray((const char *)data, size)); |
572 | } |
573 | |
574 | QWEBGL_FUNCTION(checkFramebufferStatus, GLenum, glCheckFramebufferStatus, |
575 | (GLenum) target) |
576 | { |
577 | return postEventAndQuery<&checkFramebufferStatus>(defaultValue: 0u, arguments&: 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>(arguments&: target, arguments&: level, arguments&: internalformat, arguments&: width, arguments&: height, arguments&: border, |
601 | arguments&: imageSize, arguments: 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>(arguments&: target, arguments&: level, arguments&: xoffset, arguments&: yoffset, arguments&: width, arguments&: height, arguments&: format, |
610 | arguments&: imageSize, arguments: 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 | |
622 | QWEBGL_FUNCTION_NO_PARAMS(createProgram, GLuint, glCreateProgram) |
623 | { |
624 | return postEventAndQuery<&createProgram>(defaultValue: 0u); |
625 | } |
626 | |
627 | QWEBGL_FUNCTION(createShader, GLuint, glCreateShader, |
628 | (GLenum) type) |
629 | { |
630 | return postEventAndQuery<&createShader>(defaultValue: 0u, arguments&: 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>(arguments&: n, arguments: qMakePair(x: buffers, y: 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>(arguments: qMakePair(x: framebuffers, y: 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>(arguments: qMakePair(x: renderbuffers, y: 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>(arguments: qMakePair(x: textures, y: 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>(arguments&: 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(arguments&: mode, arguments&: first, arguments&: 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, count: first + count); |
702 | QCoreApplication::postEvent(receiver: 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(arguments&: mode, arguments&: count, arguments&: type); |
712 | setVertexAttribs(event, count); |
713 | ContextData *d = currentContextData(); |
714 | if (d->boundElementArrayBuffer == 0) { |
715 | event->addParameters(arguments: 0, arguments: QByteArray(reinterpret_cast<const char *>(indices), |
716 | count * elementSize(type))); |
717 | } else { |
718 | event->addParameters(arguments: 1, arguments: uint(quintptr(indices))); |
719 | } |
720 | QCoreApplication::postEvent(receiver: QWebGLIntegrationPrivate::instance()->webSocketServer, event); |
721 | } |
722 | |
723 | QWEBGL_FUNCTION(enableVertexAttribArray, void, glEnableVertexAttribArray, |
724 | (GLuint) index) |
725 | { |
726 | postEvent<&enableVertexAttribArray>(arguments&: index); |
727 | currentContextData()->vertexAttribPointers[index].enabled = true; |
728 | } |
729 | |
730 | QWEBGL_FUNCTION_NO_PARAMS(finish, void, glFinish) |
731 | { |
732 | postEvent<&finish>(); |
733 | } |
734 | |
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>(defaultValue: QVariantList(), arguments&: n); |
755 | if (values.size() != n) |
756 | qCWarning(lc, "Failed to create buffers" ); |
757 | for (int i = 0; i < qMin(a: n, b: 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>(defaultValue: QVariantList(), arguments&: n); |
765 | if (values.size() != n) |
766 | qCWarning(lc, "Failed to create framebuffers" ); |
767 | for (int i = 0; i < qMin(a: n, b: 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>(defaultValue: QVariantList(), arguments&: n); |
775 | if (values.size() != n) |
776 | qCWarning(lc, "Failed to create render buffers" ); |
777 | for (int i = 0; i < qMin(a: n, b: 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>(defaultValue: QVariantList(), arguments&: n); |
785 | if (values.size() != n) |
786 | qCWarning(lc, "Failed to create textures" ); |
787 | for (int i = 0; i < qMin(a: n, b: 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>(defaultValue: QVariantMap(), arguments&: program, arguments&: index, arguments&: 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(a: 0, b: qMin(a: bufSize - 1, b: rname.size())); |
809 | if (length) |
810 | *length = len; |
811 | if (name) { |
812 | memcpy(dest: name, src: rname.constData(), n: 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>(defaultValue: QVariantMap(), arguments&: program, arguments&: index, arguments&: 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(a: 0, b: qMin(a: bufSize - 1, b: rname.size())); |
832 | if (length) |
833 | *length = len; |
834 | if (name) { |
835 | memcpy(dest: name, src: rname.constData(), n: 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>(defaultValue: QVariantList(), arguments&: program, arguments&: 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>(defaultValue: -1, arguments&: program, arguments&: 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(akey: 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(value: string), end = stringCache.end(); |
866 | if (it == end) |
867 | it = stringCache.insert(value: string); |
868 | return reinterpret_cast<const GLubyte *>(it->constData()); |
869 | } |
870 | } |
871 | const auto value = postEventAndQuery<&getString>(defaultValue: QByteArray(), arguments&: name); |
872 | strings.append(t: 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(varName: "QT_WEBGL_MAX_TEXTURE_SIZE" ).toUInt(ok: &ok); |
882 | if (ok) { |
883 | *data = value; |
884 | return; |
885 | } |
886 | } |
887 | const auto it = currentContextData()->cachedParameters.find(akey: 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(t&: values)) { |
896 | bool ok; |
897 | *data = integer.toInt(ok: &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>(defaultValue: 0, arguments&: pname); |
925 | } |
926 | } |
927 | |
928 | QWEBGL_FUNCTION(getBooleanv, void, glGetBooleanv, |
929 | (GLenum) pname, (GLboolean *) data) |
930 | { |
931 | const auto it = currentContextData()->cachedParameters.find(akey: 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, arguments&: pname); |
938 | } |
939 | |
940 | QWEBGL_FUNCTION(enable, void, glEnable, |
941 | (GLenum) cap) |
942 | { |
943 | if (!postEvent<&enable>(arguments&: cap)) |
944 | return; |
945 | auto it = currentContextData()->cachedParameters.find(akey: 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>(arguments&: cap)) |
956 | return; |
957 | auto it = currentContextData()->cachedParameters.find(akey: 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>(defaultValue: 0, arguments&: target, arguments&: pname); |
968 | } |
969 | |
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>(defaultValue: 0.0, arguments&: pname); |
979 | } |
980 | |
981 | QWEBGL_FUNCTION(getFramebufferAttachmentParameteriv, void, glGetFramebufferAttachmentParameteriv, |
982 | (GLenum) target, (GLenum) attachment, (GLenum) pname, (GLint *) params) |
983 | { |
984 | *params = postEventAndQuery<&getFramebufferAttachmentParameteriv>(defaultValue: 0, arguments&: target, arguments&: attachment, arguments&: pname); |
985 | } |
986 | |
987 | QWEBGL_FUNCTION(getProgramInfoLog, void, glGetProgramInfoLog, |
988 | (GLuint) program, (GLsizei) bufSize, (GLsizei *) length, (GLchar *) infoLog) |
989 | { |
990 | auto value = postEventAndQuery<&getProgramInfoLog>(defaultValue: QString(), arguments&: program); |
991 | *length = value.length(); |
992 | if (bufSize >= value.length()) |
993 | std::memcpy(dest: infoLog, src: value.constData(), n: value.length()); |
994 | } |
995 | |
996 | QWEBGL_FUNCTION(getProgramiv, void, glGetProgramiv, |
997 | (GLuint) program, (GLenum) pname, (GLint *) params) |
998 | { |
999 | *params = postEventAndQuery<&getProgramiv>(defaultValue: 0, arguments&: program, arguments&: pname); |
1000 | } |
1001 | |
1002 | QWEBGL_FUNCTION(getRenderbufferParameteriv, void, glGetRenderbufferParameteriv, |
1003 | (GLenum) target, (GLenum) pname, (GLint *) params) |
1004 | { |
1005 | *params = postEventAndQuery<&getRenderbufferParameteriv>(defaultValue: 0, arguments&: target, arguments&: 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>(defaultValue: QString(), arguments&: shader); |
1012 | *length = value.length(); |
1013 | if (bufSize >= value.length()) |
1014 | std::memcpy(dest: infoLog, src: value.constData(), n: 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>(defaultValue: QVariantMap(), arguments&: shadertype, |
1021 | arguments&: precisiontype); |
1022 | bool ok; |
1023 | range[0] = value[QStringLiteral("rangeMin" )].toInt(ok: &ok); |
1024 | if (!ok) |
1025 | qCCritical(lc, "Invalid rangeMin value" ); |
1026 | range[1] = value[QStringLiteral("rangeMax" )].toInt(ok: &ok); |
1027 | if (!ok) |
1028 | qCCritical(lc, "Invalid rangeMax value" ); |
1029 | *precision = value[QStringLiteral("precision" )].toInt(ok: &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>(defaultValue: QString(), arguments&: shader); |
1038 | *length = value.length(); |
1039 | if (bufSize >= value.length()) |
1040 | std::memcpy(dest: source, src: value.constData(), n: 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, length: &bufSize, infoLog: nullptr); |
1049 | *params = bufSize; |
1050 | return; |
1051 | } |
1052 | if (pname == GL_SHADER_SOURCE_LENGTH) { |
1053 | GLsizei bufSize = 0; |
1054 | glGetShaderSource(shader, bufSize, length: &bufSize, source: nullptr); |
1055 | *params = bufSize; |
1056 | return; |
1057 | } |
1058 | *params = postEventAndQuery<&getShaderiv>(defaultValue: 0, arguments&: shader, arguments&: pname); |
1059 | } |
1060 | |
1061 | QWEBGL_FUNCTION(getTexParameterfv, void, glGetTexParameterfv, |
1062 | (GLenum) target, (GLenum) pname, (GLfloat *) params) |
1063 | { |
1064 | *params = postEventAndQuery<&getTexParameterfv>(defaultValue: 0.f, arguments&: target, arguments&: pname); |
1065 | } |
1066 | |
1067 | QWEBGL_FUNCTION(getTexParameteriv, void, glGetTexParameteriv, |
1068 | (GLenum) target, (GLenum) pname, (GLint *) params) |
1069 | { |
1070 | *params = postEventAndQuery<&getTexParameteriv>(defaultValue: 0, arguments&: target, arguments&: pname); |
1071 | } |
1072 | |
1073 | QWEBGL_FUNCTION(getUniformLocation, GLint, glGetUniformLocation, |
1074 | (GLuint) program, (const GLchar *) name) |
1075 | { |
1076 | return postEventAndQuery<&getUniformLocation>(defaultValue: -1, arguments&: program, arguments&: name); |
1077 | } |
1078 | |
1079 | QWEBGL_FUNCTION(getUniformfv, void, glGetUniformfv, |
1080 | (GLuint) program, (GLint) location, (GLfloat *) params) |
1081 | { |
1082 | *params = postEventAndQuery<&getUniformfv>(defaultValue: 0.f, arguments&: program, arguments&: location); |
1083 | } |
1084 | |
1085 | QWEBGL_FUNCTION(getUniformiv, void, glGetUniformiv, |
1086 | (GLuint) program, (GLint) location, (GLint *) params) |
1087 | { |
1088 | *params = postEventAndQuery<&getUniformiv>(defaultValue: 0, arguments&: program, arguments&: 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(msg: "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>(defaultValue: 0.f, arguments&: index, arguments&: pname); |
1105 | } |
1106 | |
1107 | QWEBGL_FUNCTION(getVertexAttribiv, void, glGetVertexAttribiv, |
1108 | (GLuint) index, (GLenum) pname, (GLint *) params) |
1109 | { |
1110 | *params = postEventAndQuery<&getVertexAttribiv>(defaultValue: 0, arguments&: index, arguments&: 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, arguments&: buffer); |
1120 | } |
1121 | |
1122 | QWEBGL_FUNCTION(isEnabled, GLboolean, glIsEnabled, |
1123 | (GLenum) cap) |
1124 | { |
1125 | return postEventAndQuery<&isEnabled>(GL_FALSE, arguments&: cap); |
1126 | } |
1127 | |
1128 | QWEBGL_FUNCTION(isFramebuffer, GLboolean, glIsFramebuffer, |
1129 | (GLuint) framebuffer) |
1130 | { |
1131 | return postEventAndQuery<&isFramebuffer>(GL_FALSE, arguments&: framebuffer); |
1132 | } |
1133 | |
1134 | QWEBGL_FUNCTION(isProgram, GLboolean, glIsProgram, |
1135 | (GLuint) program) |
1136 | { |
1137 | return postEventAndQuery<&isProgram>(GL_FALSE, arguments&: program); |
1138 | } |
1139 | |
1140 | QWEBGL_FUNCTION(isRenderbuffer, GLboolean, glIsRenderbuffer, |
1141 | (GLuint) renderbuffer) |
1142 | { |
1143 | return postEventAndQuery<&isRenderbuffer>(GL_FALSE, arguments&: renderbuffer); |
1144 | } |
1145 | |
1146 | QWEBGL_FUNCTION(isShader, GLboolean, glIsShader, |
1147 | (GLuint) shader) |
1148 | { |
1149 | return postEventAndQuery<&isShader>(GL_FALSE, arguments&: shader); |
1150 | } |
1151 | |
1152 | QWEBGL_FUNCTION(isTexture, GLboolean, glIsTexture, |
1153 | (GLuint) texture) |
1154 | { |
1155 | return postEventAndQuery<&isTexture>(GL_FALSE, arguments&: 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>(arguments&: pname, arguments&: 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>(defaultValue: QByteArray(), arguments&: x, arguments&: y, arguments&: width, arguments&: height, arguments&: format, |
1181 | arguments&: type); |
1182 | if (!value.isEmpty()) |
1183 | std::memcpy(dest: pixels, src: value.constData(), n: value.size()); |
1184 | } |
1185 | |
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(msg: "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) |
1214 | concat = [&](int i) { fullString.append(s: QString::fromLatin1(str: string[i], size: length[i])); }; |
1215 | else |
1216 | concat = [&](int i) { fullString.append(s: QString::fromLatin1(str: string[i])); }; |
1217 | for (int i = 0; i < count; ++i) |
1218 | concat(i); |
1219 | postEvent<&shaderSource>(arguments&: shader, arguments&: 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 | pixelStorage: currentContextData()->pixelStorage); |
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(s1: pointer, s2: &zero, n: end - pointer) == 0; |
1258 | }(data, dataSize); |
1259 | postEvent<&texImage2D>(arguments&: target, arguments&: level, arguments&: internalformat, arguments&: width, arguments&: height, arguments&: border, arguments&: format, arguments&: type, |
1260 | arguments: 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(msg: "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(msg: "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>(arguments&: target, arguments&: level, arguments&: xoffset, arguments&: yoffset, arguments&: width, arguments&: height, arguments&: format, arguments&: type, |
1287 | arguments: pixels ? QByteArray(reinterpret_cast<const char *>(pixels), |
1288 | imageSize(width, height, format, type, |
1289 | pixelStorage: 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>(arguments&: location, arguments: qMakePair(x: value, y: 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>(arguments&: location, arguments: qMakePair(x: value, y: 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>(arguments&: location, arguments: qMakePair(x: value, y: 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>(arguments&: location, arguments: qMakePair(x: value, y: 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>(arguments&: location, arguments: qMakePair(x: value, y: 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>(arguments&: location, arguments: qMakePair(x: value, y: 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>(arguments&: location, arguments: qMakePair(x: value, y: 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>(arguments&: location, arguments: qMakePair(x: value, y: count * 4)); |
1363 | } |
1364 | |
1365 | QWEBGL_FUNCTION(uniformMatrix2fv, void, glUniformMatrix2fv, |
1366 | (GLint) location, (GLsizei) count, (GLboolean) transpose, (const GLfloat *) value) |
1367 | { |
1368 | postEvent<&uniformMatrix2fv>(arguments&: location, arguments&: transpose, arguments: qMakePair(x: value, y: count * 4)); |
1369 | } |
1370 | |
1371 | QWEBGL_FUNCTION(uniformMatrix3fv, void, glUniformMatrix3fv, |
1372 | (GLint) location, (GLsizei) count, (GLboolean) transpose, (const GLfloat *) value) |
1373 | { |
1374 | postEvent<&uniformMatrix3fv>(arguments&: location, arguments&: transpose, arguments: qMakePair(x: value, y: count * 9)); |
1375 | } |
1376 | |
1377 | QWEBGL_FUNCTION(uniformMatrix4fv, void, glUniformMatrix4fv, |
1378 | (GLint) location, (GLsizei) count, (GLboolean) transpose, (const GLfloat *) value) |
1379 | { |
1380 | postEvent<&uniformMatrix4fv>(arguments&: location, arguments&: transpose, arguments: qMakePair(x: value, y: 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>(arguments&: index, arguments: 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>(arguments&: index, arguments: v[0], arguments: 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>(arguments&: index, arguments: v[0], arguments: v[1], arguments: 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>(arguments&: index, arguments: v[0], arguments: v[1], arguments: v[2], arguments: 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>(arguments&: index, arguments&: size, arguments&: type, arguments&: normalized, arguments&: stride, |
1439 | arguments: uint(quintptr(pointer))); |
1440 | } |
1441 | |
1442 | QWEBGL_FUNCTION(viewport, void, glViewport, |
1443 | (GLint) x, (GLint) y, (GLsizei) width, (GLsizei) height) |
1444 | { |
1445 | postEvent<&viewport>(arguments&: x, arguments&: y, arguments&: width, arguments&: 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(msg: "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 | |
1473 | QWebGLContext::QWebGLContext(const QSurfaceFormat &format) : |
1474 | d_ptr(new QWebGLContextPrivate) |
1475 | { |
1476 | Q_D(QWebGLContext); |
1477 | d->id = d->nextId.fetchAndAddOrdered(valueToAdd: 1); |
1478 | qCDebug(lc, "Creating context %d" , d->id); |
1479 | d->surfaceFormat = format; |
1480 | d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); |
1481 | } |
1482 | |
1483 | QWebGLContext::~QWebGLContext() |
1484 | {} |
1485 | |
1486 | QSurfaceFormat QWebGLContext::format() const |
1487 | { |
1488 | Q_D(const QWebGLContext); |
1489 | return d->surfaceFormat; |
1490 | } |
1491 | |
1492 | void QWebGLContext::swapBuffers(QPlatformSurface *surface) |
1493 | { |
1494 | Q_UNUSED(surface); |
1495 | auto event = createEvent(QStringLiteral("swapBuffers" ), wait: true); |
1496 | if (!event) |
1497 | return; |
1498 | lockMutex(); |
1499 | QCoreApplication::postEvent(receiver: QWebGLIntegrationPrivate::instance()->webSocketServer, event); |
1500 | waitCondition(time: 1000); |
1501 | unlockMutex(); |
1502 | } |
1503 | |
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(value: 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(rel: std::chrono::milliseconds(100)); |
1531 | } |
1532 | s_contextData[id()].cachedParameters = future.get(); |
1533 | } |
1534 | event->addInt(value: window->window()->width()); |
1535 | event->addInt(value: window->window()->height()); |
1536 | event->addInt(value: window->winId()); |
1537 | } else if (surface->surface()->surfaceClass() == QSurface::Offscreen) { |
1538 | qCDebug(lc, "QWebGLContext::makeCurrent: QSurface::Offscreen not implemented" ); |
1539 | } |
1540 | QCoreApplication::postEvent(receiver: QWebGLIntegrationPrivate::instance()->webSocketServer, event); |
1541 | return true; |
1542 | } |
1543 | |
1544 | void QWebGLContext::doneCurrent() |
1545 | { |
1546 | postEvent<&QWebGL::makeCurrent>(arguments: 0, arguments: 0, arguments: 0, arguments: 0); |
1547 | } |
1548 | |
1549 | bool QWebGLContext::isValid() const |
1550 | { |
1551 | Q_D(const QWebGLContext); |
1552 | return d->id != -1; |
1553 | } |
1554 | |
1555 | QFunctionPointer QWebGLContext::getProcAddress(const char *procName) |
1556 | { |
1557 | const auto it = GLFunction::byName.find(akey: procName); |
1558 | return it != GLFunction::byName.end() ? (*it)->functionPointer : nullptr; |
1559 | } |
1560 | |
1561 | int QWebGLContext::id() const |
1562 | { |
1563 | Q_D(const QWebGLContext); |
1564 | return d->id; |
1565 | } |
1566 | |
1567 | QPlatformSurface *QWebGLContext::currentSurface() const |
1568 | { |
1569 | Q_D(const QWebGLContext); |
1570 | return d->currentSurface; |
1571 | } |
1572 | |
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(surface: 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(value: pointer->id()); |
1588 | |
1589 | return pointer; |
1590 | } |
1591 | |
1592 | QVariant QWebGLContext::queryValue(int id) |
1593 | { |
1594 | if (!QWebGLContextPrivate::waitingIds.contains(value: id)) { |
1595 | qCWarning(lc, "Unexpected id (%d)" , id); |
1596 | return QVariant(); |
1597 | } |
1598 | |
1599 | static auto queryValue = [](int id) |
1600 | { |
1601 | lockMutex(); |
1602 | waitCondition(time: 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(surface: 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(value: id); |
1618 | return variant; |
1619 | } |
1620 | |
1621 | QStringList QWebGLContext::supportedFunctions() |
1622 | { |
1623 | return GLFunction::remoteFunctionNames; |
1624 | } |
1625 | |
1626 | quint8 QWebGLContext::functionIndex(const QString &functionName) |
1627 | { |
1628 | const auto it = GLFunction::byName.find(akey: functionName); |
1629 | Q_ASSERT(it != GLFunction::byName.end()); |
1630 | return (*it)->id; |
1631 | } |
1632 | |
1633 | QT_END_NAMESPACE |
1634 | |