1 #include "EXWebGLMethods.h"
2 #include "EXGLContextManager.h"
3 #include "EXGLImageUtils.h"
4 #include "EXJsiArgsTransform.h"
5 #include "EXWebGLMethodsHelpers.h"
6 #include "EXWebGLRenderer.h"
7
8 #include <algorithm>
9
10 #define ARG(index, type) \
11 (argc > index ? unpackArg<type>(runtime, jsArgv + index) \
12 : throw std::runtime_error("EXGL: Too few arguments"))
13
14 #define CTX() \
15 auto result = getContext(runtime, jsThis); \
16 auto ctx = result.first; \
17 if (ctx == nullptr) { \
18 return jsi::Value::undefined(); \
19 }
20
21 #define NATIVE_METHOD(name, ...) \
22 jsi::Value glNativeMethod_##name( \
23 jsi::Runtime &runtime, const jsi::Value &jsThis, const jsi::Value *jsArgv, size_t argc)
24
25 #define SIMPLE_NATIVE_METHOD(name, func) \
26 NATIVE_METHOD(name) { \
27 CTX(); \
28 ctx->addToNextBatch(generateNativeMethod(runtime, func, jsArgv, argc)); \
29 return nullptr; \
30 }
31
32 #define UNIMPL_NATIVE_METHOD(name) \
33 NATIVE_METHOD(name) { \
34 return exglUnimplemented(#name); \
35 }
36
37 namespace expo {
38 namespace gl_cpp {
39 namespace method {
40
getContext(jsi::Runtime & runtime,const jsi::Value & jsThis)41 ContextWithLock getContext(jsi::Runtime &runtime, const jsi::Value &jsThis) {
42 double exglCtxId = jsThis.asObject(runtime).getProperty(runtime, "contextId").asNumber();
43 return ContextGet(static_cast<EXGLContextId>(exglCtxId));
44 }
45
46 // This listing follows the order in
47 // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext
48 // https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext
49
50 // The WebGL context
51 // -----------------
52
NATIVE_METHOD(getContextAttributes)53 NATIVE_METHOD(getContextAttributes) {
54 jsi::Object jsResult(runtime);
55 jsResult.setProperty(runtime, "alpha", true);
56 jsResult.setProperty(runtime, "depth", true);
57 jsResult.setProperty(runtime, "stencil", true);
58 jsResult.setProperty(runtime, "antialias", false);
59 jsResult.setProperty(runtime, "premultipliedAlpha", false);
60 return jsResult;
61 }
62
NATIVE_METHOD(isContextLost)63 NATIVE_METHOD(isContextLost) {
64 return false;
65 }
66
67 // Viewing and clipping
68 // --------------------
69
70 SIMPLE_NATIVE_METHOD(scissor, glScissor); // x, y, width, height
71
72 SIMPLE_NATIVE_METHOD(viewport, glViewport); // x, y, width, height
73
74 // State information
75 // -----------------
76
77 SIMPLE_NATIVE_METHOD(activeTexture, glActiveTexture); // texture
78
79 SIMPLE_NATIVE_METHOD(blendColor, glBlendColor); // red, green, blue, alpha
80
81 SIMPLE_NATIVE_METHOD(blendEquation, glBlendEquation); // mode
82
83 SIMPLE_NATIVE_METHOD(blendEquationSeparate, glBlendEquationSeparate); // modeRGB, modeAlpha
84
85 SIMPLE_NATIVE_METHOD(blendFunc, glBlendFunc); // sfactor, dfactor
86
87 SIMPLE_NATIVE_METHOD(blendFuncSeparate, glBlendFuncSeparate); // srcRGB, dstRGB, srcAlpha, dstAlpha
88
89 SIMPLE_NATIVE_METHOD(clearColor, glClearColor); // red, green, blue, alpha
90
91 SIMPLE_NATIVE_METHOD(clearDepth, glClearDepthf); // depth
92
93 SIMPLE_NATIVE_METHOD(clearStencil, glClearStencil); // s
94
95 SIMPLE_NATIVE_METHOD(colorMask, glColorMask); // red, green, blue, alpha
96
97 SIMPLE_NATIVE_METHOD(cullFace, glCullFace); // mode
98
99 SIMPLE_NATIVE_METHOD(depthFunc, glDepthFunc); // func
100
101 SIMPLE_NATIVE_METHOD(depthMask, glDepthMask); // flag
102
103 SIMPLE_NATIVE_METHOD(depthRange, glDepthRangef); // zNear, zFar
104
105 SIMPLE_NATIVE_METHOD(disable, glDisable); // cap
106
107 SIMPLE_NATIVE_METHOD(enable, glEnable); // cap
108
109 SIMPLE_NATIVE_METHOD(frontFace, glFrontFace); // mode
110
NATIVE_METHOD(getParameter)111 NATIVE_METHOD(getParameter) {
112 CTX();
113 auto pname = ARG(0, GLenum);
114
115 switch (pname) {
116 // Float32Array[0]
117 case GL_COMPRESSED_TEXTURE_FORMATS:
118 return TypedArray<TypedArrayKind::Float32Array>(runtime, {});
119
120 // FLoat32Array[2]
121 case GL_ALIASED_LINE_WIDTH_RANGE:
122 case GL_ALIASED_POINT_SIZE_RANGE:
123 case GL_DEPTH_RANGE: {
124 std::vector<TypedArrayBase::ContentType<TypedArrayKind::Float32Array>> glResults(2);
125 ctx->addBlockingToNextBatch([&] { glGetFloatv(pname, glResults.data()); });
126 return TypedArray<TypedArrayKind::Float32Array>(runtime, glResults);
127 }
128 // FLoat32Array[4]
129 case GL_BLEND_COLOR:
130 case GL_COLOR_CLEAR_VALUE: {
131 std::vector<TypedArrayBase::ContentType<TypedArrayKind::Float32Array>> glResults(4);
132 ctx->addBlockingToNextBatch([&] { glGetFloatv(pname, glResults.data()); });
133 return TypedArray<TypedArrayKind::Float32Array>(runtime, glResults);
134 }
135 // Int32Array[2]
136 case GL_MAX_VIEWPORT_DIMS: {
137 std::vector<TypedArrayBase::ContentType<TypedArrayKind::Int32Array>> glResults(2);
138 ctx->addBlockingToNextBatch([&] { glGetIntegerv(pname, glResults.data()); });
139 return TypedArray<TypedArrayKind::Int32Array>(runtime, glResults);
140 }
141 // Int32Array[4]
142 case GL_SCISSOR_BOX:
143 case GL_VIEWPORT: {
144 std::vector<TypedArrayBase::ContentType<TypedArrayKind::Int32Array>> glResults(4);
145 ctx->addBlockingToNextBatch([&] { glGetIntegerv(pname, glResults.data()); });
146 return TypedArray<TypedArrayKind::Int32Array>(runtime, glResults);
147 }
148 // boolean[4]
149 case GL_COLOR_WRITEMASK: {
150 GLint glResults[4];
151 ctx->addBlockingToNextBatch([&] { glGetIntegerv(pname, glResults); });
152 return jsi::Array::createWithElements(
153 runtime,
154 {jsi::Value(glResults[0]),
155 jsi::Value(glResults[1]),
156 jsi::Value(glResults[2]),
157 jsi::Value(glResults[3])});
158 }
159
160 // boolean
161 case GL_UNPACK_FLIP_Y_WEBGL:
162 return ctx->unpackFLipY;
163 case GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
164 case GL_UNPACK_COLORSPACE_CONVERSION_WEBGL:
165 return false;
166 case GL_RASTERIZER_DISCARD:
167 case GL_SAMPLE_ALPHA_TO_COVERAGE:
168 case GL_SAMPLE_COVERAGE:
169 case GL_TRANSFORM_FEEDBACK_ACTIVE:
170 case GL_TRANSFORM_FEEDBACK_PAUSED: {
171 GLint glResult;
172 ctx->addBlockingToNextBatch([&] { glGetIntegerv(pname, &glResult); });
173 return jsi::Value(glResult);
174 }
175
176 // string
177 case GL_RENDERER:
178 case GL_SHADING_LANGUAGE_VERSION:
179 case GL_VENDOR:
180 case GL_VERSION: {
181 const GLubyte *glStr;
182 ctx->addBlockingToNextBatch([&] { glStr = glGetString(pname); });
183 return jsi::String::createFromUtf8(
184 runtime, std::string(reinterpret_cast<const char *>(glStr)));
185 }
186
187 // float
188 case GL_DEPTH_CLEAR_VALUE:
189 case GL_LINE_WIDTH:
190 case GL_POLYGON_OFFSET_FACTOR:
191 case GL_POLYGON_OFFSET_UNITS:
192 case GL_SAMPLE_COVERAGE_VALUE:
193 case GL_MAX_TEXTURE_LOD_BIAS: {
194 GLfloat glFloat;
195 ctx->addBlockingToNextBatch([&] { glGetFloatv(pname, &glFloat); });
196 return static_cast<double>(glFloat);
197 }
198
199 // EXGLObjectId
200 case GL_ARRAY_BUFFER_BINDING:
201 case GL_ELEMENT_ARRAY_BUFFER_BINDING: {
202 GLint glInt;
203 ctx->addBlockingToNextBatch([&] { glGetIntegerv(pname, &glInt); });
204 for (const auto &pair : ctx->objects) {
205 if (static_cast<int>(pair.second) == glInt) {
206 return createWebGLObject(
207 runtime, EXWebGLClass::WebGLBuffer, {static_cast<double>(pair.first)});
208 }
209 }
210 return nullptr;
211 }
212
213 case GL_CURRENT_PROGRAM: {
214 GLint glInt;
215 ctx->addBlockingToNextBatch([&] { glGetIntegerv(pname, &glInt); });
216 for (const auto &pair : ctx->objects) {
217 if (static_cast<int>(pair.second) == glInt) {
218 return createWebGLObject(
219 runtime, EXWebGLClass::WebGLProgram, {static_cast<double>(pair.first)});
220 }
221 }
222 return nullptr;
223 }
224
225 // Unimplemented...
226 case GL_COPY_READ_BUFFER_BINDING:
227 case GL_COPY_WRITE_BUFFER_BINDING:
228 case GL_DRAW_FRAMEBUFFER_BINDING:
229 case GL_READ_FRAMEBUFFER_BINDING:
230 case GL_RENDERBUFFER_BINDING:
231 case GL_SAMPLER_BINDING:
232 case GL_TEXTURE_BINDING_2D_ARRAY:
233 case GL_TEXTURE_BINDING_2D:
234 case GL_TEXTURE_BINDING_3D:
235 case GL_TEXTURE_BINDING_CUBE_MAP:
236 case GL_TRANSFORM_FEEDBACK_BINDING:
237 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
238 case GL_UNIFORM_BUFFER_BINDING:
239 case GL_VERTEX_ARRAY_BINDING:
240 throw std::runtime_error(
241 "EXGL: getParameter() doesn't support gl." + std::to_string(pname) + " yet!");
242
243 // int
244 default: {
245 GLint glInt;
246 ctx->addBlockingToNextBatch([&] { glGetIntegerv(pname, &glInt); });
247 return jsi::Value(glInt);
248 }
249 }
250 }
251
NATIVE_METHOD(getError)252 NATIVE_METHOD(getError) {
253 CTX();
254 GLenum glResult;
255 ctx->addBlockingToNextBatch([&] { glResult = glGetError(); });
256 return static_cast<double>(glResult);
257 }
258
259 SIMPLE_NATIVE_METHOD(hint, glHint); // target, mode
260
NATIVE_METHOD(isEnabled)261 NATIVE_METHOD(isEnabled) {
262 CTX();
263 auto cap = ARG(0, GLenum);
264 GLboolean glResult;
265 ctx->addBlockingToNextBatch([&] { glResult = glIsEnabled(cap); });
266 return glResult == GL_TRUE;
267 }
268
269 SIMPLE_NATIVE_METHOD(lineWidth, glLineWidth); // width
270
NATIVE_METHOD(pixelStorei)271 NATIVE_METHOD(pixelStorei) {
272 CTX();
273 auto pname = ARG(0, GLenum);
274 switch (pname) {
275 case GL_UNPACK_FLIP_Y_WEBGL: {
276 ctx->unpackFLipY = ARG(1, GLboolean);
277 break;
278 }
279 case GL_UNPACK_ALIGNMENT: {
280 auto param = ARG(1, GLint);
281 ctx->addToNextBatch([=] {
282 glPixelStorei(GL_UNPACK_ALIGNMENT, param);
283 });
284 break;
285 }
286 default:
287 jsConsoleLog(runtime, { jsi::String::createFromUtf8(runtime, "EXGL: gl.pixelStorei() doesn't support this parameter yet!") });
288 }
289 return nullptr;
290 }
291
292 SIMPLE_NATIVE_METHOD(polygonOffset, glPolygonOffset); // factor, units
293
294 SIMPLE_NATIVE_METHOD(sampleCoverage, glSampleCoverage); // value, invert
295
296 SIMPLE_NATIVE_METHOD(stencilFunc, glStencilFunc); // func, ref, mask
297
298 SIMPLE_NATIVE_METHOD(stencilFuncSeparate, glStencilFuncSeparate); // face, func, ref, mask
299
300 SIMPLE_NATIVE_METHOD(stencilMask, glStencilMask); // mask
301
302 SIMPLE_NATIVE_METHOD(stencilMaskSeparate, glStencilMaskSeparate); // face, mask
303
304 SIMPLE_NATIVE_METHOD(stencilOp, glStencilOp) // fail, zfail, zpass
305
306 SIMPLE_NATIVE_METHOD(stencilOpSeparate, glStencilOpSeparate); // face, fail, zfail, zpass
307
308 // Buffers
309 // -------
310
NATIVE_METHOD(bindBuffer)311 NATIVE_METHOD(bindBuffer) {
312 CTX();
313 auto target = ARG(0, GLenum);
314 auto buffer = ARG(1, EXWebGLClass);
315 ctx->addToNextBatch([=] { glBindBuffer(target, ctx->lookupObject(buffer)); });
316 return nullptr;
317 }
318
NATIVE_METHOD(bufferData)319 NATIVE_METHOD(bufferData) {
320 CTX();
321 auto target = ARG(0, GLenum);
322 auto &sizeOrData = ARG(1, const jsi::Value &);
323 auto usage = ARG(2, GLenum);
324
325 if (sizeOrData.isNumber()) {
326 GLsizeiptr length = sizeOrData.getNumber();
327 ctx->addToNextBatch([=] { glBufferData(target, length, nullptr, usage); });
328 } else if (sizeOrData.isNull() || sizeOrData.isUndefined()) {
329 ctx->addToNextBatch([=] { glBufferData(target, 0, nullptr, usage); });
330 } else if (sizeOrData.isObject()) {
331 auto data = rawTypedArray(runtime, sizeOrData.getObject(runtime));
332 ctx->addToNextBatch(
333 [=, data{std::move(data)}] { glBufferData(target, data.size(), data.data(), usage); });
334 }
335 return nullptr;
336 }
337
NATIVE_METHOD(bufferSubData)338 NATIVE_METHOD(bufferSubData) {
339 CTX();
340 auto target = ARG(0, GLenum);
341 auto offset = ARG(1, GLintptr);
342 if (ARG(2, const jsi::Value &).isNull()) {
343 ctx->addToNextBatch([=] { glBufferSubData(target, offset, 0, nullptr); });
344 } else {
345 auto data = rawTypedArray(runtime, ARG(2, jsi::Object));
346 ctx->addToNextBatch(
347 [=, data{std::move(data)}] { glBufferSubData(target, offset, data.size(), data.data()); });
348 }
349 return nullptr;
350 }
351
NATIVE_METHOD(createBuffer)352 NATIVE_METHOD(createBuffer) {
353 CTX();
354 return exglGenObject(ctx, runtime, glGenBuffers, EXWebGLClass::WebGLBuffer);
355 }
356
NATIVE_METHOD(deleteBuffer)357 NATIVE_METHOD(deleteBuffer) {
358 CTX();
359 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteBuffers);
360 }
361
NATIVE_METHOD(getBufferParameter)362 NATIVE_METHOD(getBufferParameter) {
363 CTX();
364 auto target = ARG(0, GLenum);
365 auto pname = ARG(1, GLenum);
366 GLint glResult;
367 ctx->addBlockingToNextBatch([&] { glGetBufferParameteriv(target, pname, &glResult); });
368 return jsi::Value(glResult);
369 }
370
NATIVE_METHOD(isBuffer)371 NATIVE_METHOD(isBuffer) {
372 CTX();
373 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsBuffer);
374 }
375
376 // Buffers (WebGL2)
377
378 SIMPLE_NATIVE_METHOD(
379 copyBufferSubData,
380 glCopyBufferSubData) // readTarget, writeTarget, readOffset, writeOffset, size
381
382 // glGetBufferSubData is not available in OpenGL ES
383 UNIMPL_NATIVE_METHOD(getBufferSubData);
384
385 // Framebuffers
386 // ------------
387
NATIVE_METHOD(bindFramebuffer)388 NATIVE_METHOD(bindFramebuffer) {
389 CTX();
390 auto target = ARG(0, GLenum);
391 auto framebuffer = ARG(1, EXWebGLClass);
392 ctx->addToNextBatch([=] {
393 glBindFramebuffer(
394 target, framebuffer == 0 ? ctx->defaultFramebuffer : ctx->lookupObject(framebuffer));
395 });
396 return nullptr;
397 }
398
NATIVE_METHOD(checkFramebufferStatus)399 NATIVE_METHOD(checkFramebufferStatus) {
400 CTX();
401 auto target = ARG(0, GLenum);
402 GLenum glResult;
403 ctx->addBlockingToNextBatch([&] { glResult = glCheckFramebufferStatus(target); });
404 return static_cast<double>(glResult);
405 }
406
NATIVE_METHOD(createFramebuffer)407 NATIVE_METHOD(createFramebuffer) {
408 CTX();
409 return exglGenObject(ctx, runtime, glGenFramebuffers, EXWebGLClass::WebGLFramebuffer);
410 }
411
NATIVE_METHOD(deleteFramebuffer)412 NATIVE_METHOD(deleteFramebuffer) {
413 CTX();
414 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteFramebuffers);
415 }
416
NATIVE_METHOD(framebufferRenderbuffer)417 NATIVE_METHOD(framebufferRenderbuffer) {
418 CTX();
419 auto target = ARG(0, GLenum);
420 auto attachment = ARG(1, GLenum);
421 auto renderbuffertarget = ARG(2, GLenum);
422 auto fRenderbuffer = ARG(3, EXWebGLClass);
423 ctx->addToNextBatch([=] {
424 GLuint renderbuffer = ctx->lookupObject(fRenderbuffer);
425 glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
426 });
427 return nullptr;
428 }
429
430 NATIVE_METHOD(framebufferTexture2D, 5) {
431 CTX();
432 auto target = ARG(0, GLenum);
433 auto attachment = ARG(1, GLenum);
434 auto textarget = ARG(2, GLenum);
435 auto fTexture = ARG(3, EXWebGLClass);
436 auto level = ARG(4, GLint);
__anon33f747aa1902null437 ctx->addToNextBatch([=] {
438 glFramebufferTexture2D(target, attachment, textarget, ctx->lookupObject(fTexture), level);
439 });
440 return nullptr;
441 }
442
443 UNIMPL_NATIVE_METHOD(getFramebufferAttachmentParameter)
444
NATIVE_METHOD(isFramebuffer)445 NATIVE_METHOD(isFramebuffer) {
446 CTX();
447 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsFramebuffer);
448 }
449
NATIVE_METHOD(readPixels)450 NATIVE_METHOD(readPixels) {
451 CTX();
452 auto x = ARG(0, GLint);
453 auto y = ARG(1, GLint);
454 auto width = ARG(2, GLuint); // GLsizei allows negative values
455 auto height = ARG(3, GLuint);
456 auto format = ARG(4, GLenum);
457 auto type = ARG(5, GLenum);
458 size_t byteLength = width * height * bytesPerPixel(type, format);
459 std::vector<uint8_t> pixels(byteLength);
460 ctx->addBlockingToNextBatch(
461 [&] { glReadPixels(x, y, width, height, format, type, pixels.data()); });
462
463 TypedArrayBase arr = ARG(6, TypedArrayBase);
464 jsi::ArrayBuffer buffer = arr.getBuffer(runtime);
465 arrayBufferUpdate(runtime, buffer, pixels, arr.byteOffset(runtime));
466 return nullptr;
467 }
468
469 // Framebuffers (WebGL2)
470 // ---------------------
471
472 SIMPLE_NATIVE_METHOD(blitFramebuffer, glBlitFramebuffer);
473 // srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter
474
NATIVE_METHOD(framebufferTextureLayer)475 NATIVE_METHOD(framebufferTextureLayer) {
476 CTX();
477 auto target = ARG(0, GLenum);
478 auto attachment = ARG(1, GLenum);
479 auto texture = ARG(2, EXWebGLClass);
480 auto level = ARG(3, GLint);
481 auto layer = ARG(4, GLint);
482 ctx->addToNextBatch([=] {
483 glFramebufferTextureLayer(target, attachment, ctx->lookupObject(texture), level, layer);
484 });
485 return nullptr;
486 }
487
NATIVE_METHOD(invalidateFramebuffer)488 NATIVE_METHOD(invalidateFramebuffer) {
489 CTX();
490 auto target = ARG(0, GLenum);
491 auto jsAttachments = ARG(1, jsi::Array);
492
493 std::vector<GLenum> attachments(jsAttachments.size(runtime));
494 for (size_t i = 0; i < attachments.size(); i++) {
495 attachments[i] = jsAttachments.getValueAtIndex(runtime, i).asNumber();
496 }
497 ctx->addToNextBatch([=, attachaments{std::move(attachments)}] {
498 glInvalidateFramebuffer(target, static_cast<GLsizei>(attachments.size()), attachments.data());
499 });
500 return nullptr; // breaking change TypedArray -> Array (bug in previous implementation)
501 }
502
NATIVE_METHOD(invalidateSubFramebuffer)503 NATIVE_METHOD(invalidateSubFramebuffer) {
504 CTX();
505 auto target = ARG(0, GLenum);
506 auto jsAttachments = ARG(1, jsi::Array);
507 auto x = ARG(2, GLint);
508 auto y = ARG(3, GLint);
509 auto width = ARG(4, GLint);
510 auto height = ARG(5, GLint);
511 std::vector<GLenum> attachments(jsAttachments.size(runtime));
512 for (size_t i = 0; i < attachments.size(); i++) {
513 attachments[i] = jsAttachments.getValueAtIndex(runtime, i).asNumber();
514 }
515 ctx->addToNextBatch([=, attachments{std::move(attachments)}] {
516 glInvalidateSubFramebuffer(
517 target, static_cast<GLsizei>(attachments.size()), attachments.data(), x, y, width, height);
518 });
519 return nullptr;
520 }
521
522 SIMPLE_NATIVE_METHOD(readBuffer, glReadBuffer); // mode
523
524 // Renderbuffers
525 // -------------
526
NATIVE_METHOD(bindRenderbuffer)527 NATIVE_METHOD(bindRenderbuffer) {
528 CTX();
529 auto target = ARG(0, GLenum);
530 auto fRenderbuffer = ARG(1, EXWebGLClass);
531 ctx->addToNextBatch([=] { glBindRenderbuffer(target, ctx->lookupObject(fRenderbuffer)); });
532 return nullptr;
533 }
534
NATIVE_METHOD(createRenderbuffer)535 NATIVE_METHOD(createRenderbuffer) {
536 CTX();
537 return exglGenObject(ctx, runtime, glGenRenderbuffers, EXWebGLClass::WebGLRenderbuffer);
538 }
539
NATIVE_METHOD(deleteRenderbuffer)540 NATIVE_METHOD(deleteRenderbuffer) {
541 CTX();
542 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteRenderbuffers);
543 }
544
545 UNIMPL_NATIVE_METHOD(getRenderbufferParameter)
546
NATIVE_METHOD(isRenderbuffer)547 NATIVE_METHOD(isRenderbuffer) {
548 CTX();
549 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsRenderbuffer);
550 }
551
NATIVE_METHOD(renderbufferStorage)552 NATIVE_METHOD(renderbufferStorage) {
553 CTX();
554 auto target = ARG(0, GLenum);
555 auto internalformat = ARG(1, GLint);
556 auto width = ARG(2, GLsizei);
557 auto height = ARG(3, GLsizei);
558
559 // WebGL allows `GL_DEPTH_STENCIL` flag to be passed here,
560 // however OpenGL ES seems to require sized format, so we fall back to `GL_DEPTH24_STENCIL8`.
561 internalformat = internalformat == GL_DEPTH_STENCIL ? GL_DEPTH24_STENCIL8 : internalformat;
562
563 ctx->addToNextBatch([=] { glRenderbufferStorage(target, internalformat, width, height); });
564 return nullptr;
565 }
566
567 // Renderbuffers (WebGL2)
568 // ----------------------
569
NATIVE_METHOD(getInternalformatParameter)570 NATIVE_METHOD(getInternalformatParameter) {
571 CTX();
572 auto target = ARG(0, GLenum);
573 auto internalformat = ARG(1, GLenum);
574 auto pname = ARG(2, GLenum);
575
576 std::vector<TypedArrayBase::ContentType<TypedArrayKind::Int32Array>> glResults;
577 ctx->addBlockingToNextBatch([&] {
578 GLint count;
579 glGetInternalformativ(target, internalformat, GL_NUM_SAMPLE_COUNTS, 1, &count);
580 glResults.resize(count);
581 glGetInternalformativ(target, internalformat, pname, count, glResults.data());
582 });
583
584 return TypedArray<TypedArrayKind::Int32Array>(runtime, glResults);
585 }
586
587 UNIMPL_NATIVE_METHOD(renderbufferStorageMultisample)
588
589 // Textures
590 // --------
591
NATIVE_METHOD(bindTexture)592 NATIVE_METHOD(bindTexture) {
593 CTX();
594 auto target = ARG(0, GLenum);
595 auto texture = ARG(1, EXWebGLClass);
596 ctx->addToNextBatch([=] { glBindTexture(target, ctx->lookupObject(texture)); });
597 return nullptr;
598 }
599
600 UNIMPL_NATIVE_METHOD(compressedTexImage2D)
601
602 UNIMPL_NATIVE_METHOD(compressedTexSubImage2D)
603
604 SIMPLE_NATIVE_METHOD(
605 copyTexImage2D,
606 glCopyTexImage2D); // target, level, internalformat, x, y, width, height, border
607
SIMPLE_NATIVE_METHOD(copyTexSubImage2D,glCopyTexSubImage2D)608 SIMPLE_NATIVE_METHOD(
609 copyTexSubImage2D,
610 glCopyTexSubImage2D) // target, level, xoffset, yoffset, x, y, width, height
611
612 NATIVE_METHOD(createTexture) {
613 CTX();
614 return exglGenObject(ctx, runtime, glGenTextures, EXWebGLClass::WebGLTexture);
615 }
616
NATIVE_METHOD(deleteTexture)617 NATIVE_METHOD(deleteTexture) {
618 CTX();
619 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteTextures);
620 }
621
SIMPLE_NATIVE_METHOD(generateMipmap,glGenerateMipmap)622 SIMPLE_NATIVE_METHOD(generateMipmap, glGenerateMipmap) // target
623
624 UNIMPL_NATIVE_METHOD(getTexParameter)
625
626 NATIVE_METHOD(isTexture) {
627 CTX();
628 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsTexture);
629 }
630
631 NATIVE_METHOD(texImage2D, 6) {
632 CTX();
633 auto target = ARG(0, GLenum);
634 auto level = ARG(1, GLint);
635 auto internalformat = ARG(2, GLint);
636 if (argc == 9) {
637 auto width = ARG(3, GLsizei);
638 auto height = ARG(4, GLsizei);
639 auto border = ARG(5, GLsizei);
640 auto format = ARG(6, GLenum);
641 auto type = ARG(7, GLenum);
642 if (ARG(8, const jsi::Value &).isNull()) {
__anon33f747aa2202null643 ctx->addToNextBatch([=] {
644 glTexImage2D(target, level, internalformat, width, height, border, format, type, nullptr);
645 });
646 return nullptr;
647 }
648 auto data = ARG(8, jsi::Object);
649
650 if (data.isArrayBuffer(runtime) || isTypedArray(runtime, data)) {
651 std::vector<uint8_t> vec = rawTypedArray(runtime, std::move(data));
652 if (ctx->unpackFLipY) {
653 flipPixels(vec.data(), width * bytesPerPixel(type, format), height);
654 }
__anon33f747aa2302null655 ctx->addToNextBatch([=, vec{std::move(vec)}] {
656 glTexImage2D(
657 target, level, internalformat, width, height, border, format, type, vec.data());
658 });
659 } else {
660 auto image = loadImage(runtime, data, &width, &height, nullptr);
661 if (ctx->unpackFLipY) {
662 flipPixels(image.get(), width * bytesPerPixel(type, format), height);
663 }
__anon33f747aa2402null664 ctx->addToNextBatch([=] {
665 glTexImage2D(
666 target, level, internalformat, width, height, border, format, type, image.get());
667 });
668 }
669 } else if (argc == 6) {
670 auto format = ARG(3, GLenum);
671 auto type = ARG(4, GLenum);
672 auto data = ARG(5, jsi::Object);
673 GLsizei width = 0, height = 0, border = 0;
674 auto image = loadImage(runtime, data, &width, &height, nullptr);
675 if (ctx->unpackFLipY) {
676 flipPixels(image.get(), width * bytesPerPixel(type, format), height);
677 }
__anon33f747aa2502null678 ctx->addToNextBatch([=] {
679 glTexImage2D(target, level, internalformat, width, height, border, format, type, image.get());
680 });
681 } else {
682 throw std::runtime_error("EXGL: Invalid number of arguments to gl.texImage2D()!");
683 }
684 return nullptr;
685 }
686
687 NATIVE_METHOD(texSubImage2D, 6) {
688 CTX();
689 auto target = ARG(0, GLenum);
690 auto level = ARG(1, GLint);
691 auto xoffset = ARG(2, GLint);
692 auto yoffset = ARG(3, GLint);
693 if (argc == 9) {
694 auto width = ARG(4, GLsizei);
695 auto height = ARG(5, GLsizei);
696 auto format = ARG(6, GLenum);
697 auto type = ARG(7, GLenum);
698 if (ARG(8, const jsi::Value &).isNull()) {
__anon33f747aa2602null699 ctx->addToNextBatch([=] {
700 auto empty = std::make_unique<uint8_t>(width * height * bytesPerPixel(type, format));
701 std::memset(empty.get(), 0, width * height * bytesPerPixel(type, format));
702 glTexImage2D(target, level, xoffset, yoffset, width, height, format, type, empty.get());
703 });
704 return nullptr;
705 }
706
707 auto data = ARG(8, jsi::Object);
708
709 if (data.isArrayBuffer(runtime) || isTypedArray(runtime, data)) {
710 std::vector<uint8_t> vec = rawTypedArray(runtime, std::move(data));
711 if (ctx->unpackFLipY) {
712 flipPixels(vec.data(), width * bytesPerPixel(type, format), height);
713 }
__anon33f747aa2702null714 ctx->addToNextBatch([=, vec{std::move(vec)}] {
715 glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, vec.data());
716 });
717 } else {
718 auto image = loadImage(runtime, data, &width, &height, nullptr);
719 if (ctx->unpackFLipY) {
720 flipPixels(image.get(), width * bytesPerPixel(type, format), height);
721 }
__anon33f747aa2802null722 ctx->addToNextBatch([=] {
723 glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, image.get());
724 });
725 }
726 } else if (argc == 7) {
727 auto format = ARG(4, GLenum);
728 auto type = ARG(5, GLenum);
729 auto data = ARG(6, jsi::Object);
730 GLsizei width = 0, height = 0;
731 auto image = loadImage(runtime, data, &width, &height, nullptr);
732 if (ctx->unpackFLipY) {
733 flipPixels(image.get(), width * bytesPerPixel(type, format), height);
734 }
__anon33f747aa2902null735 ctx->addToNextBatch([=] {
736 glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, image.get());
737 });
738 } else {
739 throw std::runtime_error("EXGL: Invalid number of arguments to gl.texSubImage2D()!");
740 }
741 return nullptr;
742 }
743
744 SIMPLE_NATIVE_METHOD(texParameterf, glTexParameterf); // target, pname, param
745
746 SIMPLE_NATIVE_METHOD(texParameteri, glTexParameteri); // target, pname, param
747
748 // Textures (WebGL2)
749 // -----------------
750
751 SIMPLE_NATIVE_METHOD(texStorage2D, glTexStorage2D); // target, levels, internalformat, width, height
752
753 SIMPLE_NATIVE_METHOD(
754 texStorage3D,
755 glTexStorage3D); // target, levels, internalformat, width, height, depth
756
NATIVE_METHOD(texImage3D)757 NATIVE_METHOD(texImage3D) {
758 CTX();
759 auto target = ARG(0, GLenum);
760 auto level = ARG(1, GLint);
761 auto internalformat = ARG(2, GLint);
762 auto width = ARG(3, GLsizei);
763 auto height = ARG(4, GLsizei);
764 auto depth = ARG(5, GLsizei);
765 auto border = ARG(6, GLsizei);
766 auto format = ARG(7, GLenum);
767 auto type = ARG(8, GLenum);
768
769 if (ARG(9, const jsi::Value &).isNull()) {
770 ctx->addToNextBatch([=] {
771 glTexImage3D(
772 target, level, internalformat, width, height, depth, border, format, type, nullptr);
773 });
774 return nullptr;
775 }
776 auto data = ARG(9, jsi::Object);
777 auto flip = [&](uint8_t *data) {
778 GLubyte *texelLayer = data;
779 for (int z = 0; z < depth; z++) {
780 flipPixels(texelLayer, width * bytesPerPixel(type, format), height);
781 texelLayer += bytesPerPixel(type, format) * width * height;
782 }
783 };
784
785 if (data.isArrayBuffer(runtime) || isTypedArray(runtime, data)) {
786 std::vector<uint8_t> vec = rawTypedArray(runtime, std::move(data));
787 if (ctx->unpackFLipY) {
788 flip(vec.data());
789 }
790 ctx->addToNextBatch([=, vec{std::move(vec)}] {
791 glTexImage3D(
792 target, level, internalformat, width, height, depth, border, format, type, vec.data());
793 });
794 } else {
795 auto image = loadImage(runtime, data, &width, &height, nullptr);
796 if (ctx->unpackFLipY) {
797 flip(image.get());
798 }
799 ctx->addToNextBatch([=] {
800 glTexImage3D(
801 target, level, internalformat, width, height, depth, border, format, type, image.get());
802 });
803 }
804 return nullptr;
805 }
806
NATIVE_METHOD(texSubImage3D)807 NATIVE_METHOD(texSubImage3D) {
808 CTX();
809 auto target = ARG(0, GLenum);
810 auto level = ARG(1, GLint);
811 auto xoffset = ARG(2, GLint);
812 auto yoffset = ARG(3, GLint);
813 auto zoffset = ARG(4, GLint);
814 auto width = ARG(5, GLsizei);
815 auto height = ARG(6, GLsizei);
816 auto depth = ARG(7, GLsizei);
817 auto format = ARG(8, GLenum);
818 auto type = ARG(9, GLenum);
819
820 if (ARG(10, const jsi::Value &).isNull()) {
821 ctx->addToNextBatch([=] {
822 auto empty = std::make_unique<uint8_t>(width * height * depth * bytesPerPixel(type, format));
823 std::memset(empty.get(), 0, width * height * depth * bytesPerPixel(type, format));
824 auto ptr = empty.get();
825 glTexSubImage3D(
826 target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, ptr);
827 });
828 return nullptr;
829 }
830 auto data = ARG(10, jsi::Object);
831 auto flip = [&](uint8_t *data) {
832 GLubyte *texelLayer = data;
833 for (int z = 0; z < depth; z++) {
834 flipPixels(texelLayer, width * bytesPerPixel(type, format), height);
835 texelLayer += bytesPerPixel(type, format) * width * height;
836 }
837 };
838
839 if (data.isArrayBuffer(runtime) || isTypedArray(runtime, data)) {
840 std::vector<uint8_t> vec = rawTypedArray(runtime, std::move(data));
841 if (ctx->unpackFLipY) {
842 flip(vec.data());
843 }
844 ctx->addToNextBatch([=, vec{std::move(vec)}] {
845 glTexSubImage3D(
846 target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, vec.data());
847 });
848 } else {
849 auto image = loadImage(runtime, data, &width, &height, nullptr);
850 if (ctx->unpackFLipY) {
851 flip(image.get());
852 }
853 ctx->addToNextBatch([=] {
854 glTexSubImage3D(
855 target,
856 level,
857 xoffset,
858 yoffset,
859 zoffset,
860 width,
861 height,
862 depth,
863 format,
864 type,
865 image.get());
866 });
867 }
868 return nullptr;
869 }
870
871 SIMPLE_NATIVE_METHOD(
872 copyTexSubImage3D,
873 glCopyTexSubImage3D); // target, level, xoffset, yoffset, zoffset, x, y, width, height
874
875 UNIMPL_NATIVE_METHOD(compressedTexImage3D)
876
UNIMPL_NATIVE_METHOD(compressedTexSubImage3D)877 UNIMPL_NATIVE_METHOD(compressedTexSubImage3D)
878
879 // Programs and shaders
880 // --------------------
881
882 NATIVE_METHOD(attachShader) {
883 CTX();
884 auto program = ARG(0, EXWebGLClass);
885 auto shader = ARG(1, EXWebGLClass);
886 ctx->addToNextBatch(
887 [=] { glAttachShader(ctx->lookupObject(program), ctx->lookupObject(shader)); });
888 return nullptr;
889 }
890
NATIVE_METHOD(bindAttribLocation)891 NATIVE_METHOD(bindAttribLocation) {
892 CTX();
893 auto program = ARG(0, EXWebGLClass);
894 auto index = ARG(1, GLuint);
895 auto name = ARG(2, std::string);
896 ctx->addToNextBatch([=, name{std::move(name)}] {
897 glBindAttribLocation(ctx->lookupObject(program), index, name.c_str());
898 });
899 return nullptr;
900 }
901
NATIVE_METHOD(compileShader)902 NATIVE_METHOD(compileShader) {
903 CTX();
904 auto shader = ARG(0, EXWebGLClass);
905 ctx->addToNextBatch([=] { glCompileShader(ctx->lookupObject(shader)); });
906 return nullptr;
907 }
908
NATIVE_METHOD(createProgram)909 NATIVE_METHOD(createProgram) {
910 CTX();
911 return exglCreateObject(ctx, runtime, glCreateProgram, EXWebGLClass::WebGLProgram);
912 }
913
NATIVE_METHOD(createShader)914 NATIVE_METHOD(createShader) {
915 CTX();
916 auto type = ARG(0, GLenum);
917 if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER) {
918 return exglCreateObject(
919 ctx, runtime, std::bind(glCreateShader, type), EXWebGLClass::WebGLShader);
920 } else {
921 throw std::runtime_error("unknown shader type passed to function");
922 }
923 }
924
NATIVE_METHOD(deleteProgram)925 NATIVE_METHOD(deleteProgram) {
926 CTX();
927 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteProgram);
928 }
929
NATIVE_METHOD(deleteShader)930 NATIVE_METHOD(deleteShader) {
931 CTX();
932 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteShader);
933 }
934
NATIVE_METHOD(detachShader)935 NATIVE_METHOD(detachShader) {
936 CTX();
937 auto program = ARG(0, EXWebGLClass);
938 auto shader = ARG(1, EXWebGLClass);
939 ctx->addToNextBatch(
940 [=] { glDetachShader(ctx->lookupObject(program), ctx->lookupObject(shader)); });
941 return nullptr;
942 }
943
NATIVE_METHOD(getAttachedShaders)944 NATIVE_METHOD(getAttachedShaders) {
945 CTX();
946 auto fProgram = ARG(0, EXWebGLClass);
947
948 GLint count;
949 std::vector<GLuint> glResults;
950 ctx->addBlockingToNextBatch([&] {
951 GLuint program = ctx->lookupObject(fProgram);
952 glGetProgramiv(program, GL_ATTACHED_SHADERS, &count);
953 glResults.resize(count);
954 glGetAttachedShaders(program, count, nullptr, glResults.data());
955 });
956
957 jsi::Array jsResults(runtime, count);
958 for (auto i = 0; i < count; ++i) {
959 EXGLObjectId exglObjId = 0;
960 for (const auto &pair : ctx->objects) {
961 if (pair.second == glResults[i]) {
962 exglObjId = pair.first;
963 }
964 }
965 if (exglObjId == 0) {
966 throw std::runtime_error(
967 "EXGL: Internal error: couldn't find EXGLObjectId "
968 "associated with shader in getAttachedShaders()!");
969 }
970 jsResults.setValueAtIndex(
971 runtime,
972 i,
973 createWebGLObject(runtime, EXWebGLClass::WebGLShader, {static_cast<double>(exglObjId)}));
974 }
975 return jsResults;
976 }
977
NATIVE_METHOD(getProgramParameter)978 NATIVE_METHOD(getProgramParameter) {
979 CTX();
980 auto fProgram = ARG(0, EXWebGLClass);
981 auto pname = ARG(1, GLenum);
982 GLint glResult;
983 ctx->addBlockingToNextBatch(
984 [&] { glGetProgramiv(ctx->lookupObject(fProgram), pname, &glResult); });
985 if (pname == GL_DELETE_STATUS || pname == GL_LINK_STATUS || pname == GL_VALIDATE_STATUS) {
986 return glResult == GL_TRUE;
987 } else {
988 return glResult;
989 }
990 }
991
NATIVE_METHOD(getShaderParameter)992 NATIVE_METHOD(getShaderParameter) {
993 CTX();
994 auto fShader = ARG(0, EXWebGLClass);
995 auto pname = ARG(1, GLenum);
996 GLint glResult;
997 ctx->addBlockingToNextBatch([&] { glGetShaderiv(ctx->lookupObject(fShader), pname, &glResult); });
998 if (pname == GL_DELETE_STATUS || pname == GL_COMPILE_STATUS) {
999 return glResult == GL_TRUE;
1000 } else {
1001 return glResult;
1002 }
1003 }
1004
NATIVE_METHOD(getShaderPrecisionFormat)1005 NATIVE_METHOD(getShaderPrecisionFormat) {
1006 CTX();
1007 auto shaderType = ARG(0, GLenum);
1008 auto precisionType = ARG(1, GLenum);
1009
1010 GLint range[2], precision;
1011 ctx->addBlockingToNextBatch(
1012 [&] { glGetShaderPrecisionFormat(shaderType, precisionType, range, &precision); });
1013
1014 jsi::Object jsResult =
1015 createWebGLObject(runtime, EXWebGLClass::WebGLShaderPrecisionFormat, {}).asObject(runtime);
1016 jsResult.setProperty(runtime, "rangeMin", jsi::Value(range[0]));
1017 jsResult.setProperty(runtime, "rangeMax", jsi::Value(range[1]));
1018 jsResult.setProperty(runtime, "precision", jsi::Value(precision));
1019 return jsResult;
1020 }
1021
NATIVE_METHOD(getProgramInfoLog)1022 NATIVE_METHOD(getProgramInfoLog) {
1023 CTX();
1024 auto fObj = ARG(0, EXWebGLClass);
1025 std::string str;
1026 ctx->addBlockingToNextBatch([&] {
1027 GLuint obj = ctx->lookupObject(fObj);
1028 GLint length;
1029 glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &length);
1030 str.resize(length > 0 ? length - 1 : 0);
1031 glGetProgramInfoLog(obj, length, nullptr, &str[0]);
1032 });
1033 return jsi::String::createFromUtf8(runtime, str);
1034 }
1035
NATIVE_METHOD(getShaderInfoLog)1036 NATIVE_METHOD(getShaderInfoLog) {
1037 CTX();
1038 auto fObj = ARG(0, EXWebGLClass);
1039 std::string str;
1040 ctx->addBlockingToNextBatch([&] {
1041 GLuint obj = ctx->lookupObject(fObj);
1042 GLint length;
1043 glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &length);
1044 str.resize(length > 0 ? length - 1 : 0);
1045 glGetShaderInfoLog(obj, length, nullptr, &str[0]);
1046 });
1047 return jsi::String::createFromUtf8(runtime, str);
1048 }
1049
NATIVE_METHOD(getShaderSource)1050 NATIVE_METHOD(getShaderSource) {
1051 CTX();
1052 auto fObj = ARG(0, EXWebGLClass);
1053 std::string str;
1054 ctx->addBlockingToNextBatch([&] {
1055 GLuint obj = ctx->lookupObject(fObj);
1056 GLint length;
1057 glGetShaderiv(obj, GL_SHADER_SOURCE_LENGTH, &length);
1058 str.resize(length > 0 ? length - 1 : 0);
1059 glGetShaderSource(obj, length, nullptr, &str[0]);
1060 });
1061 return jsi::String::createFromUtf8(runtime, str);
1062 }
1063
NATIVE_METHOD(isShader)1064 NATIVE_METHOD(isShader) {
1065 CTX();
1066 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsShader);
1067 }
1068
NATIVE_METHOD(isProgram)1069 NATIVE_METHOD(isProgram) {
1070 CTX();
1071 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsProgram);
1072 }
1073
NATIVE_METHOD(linkProgram)1074 NATIVE_METHOD(linkProgram) {
1075 CTX();
1076 auto fProgram = ARG(0, EXWebGLClass);
1077 ctx->addToNextBatch([=] { glLinkProgram(ctx->lookupObject(fProgram)); });
1078 return nullptr;
1079 }
1080
NATIVE_METHOD(shaderSource)1081 NATIVE_METHOD(shaderSource) {
1082 CTX();
1083 auto fShader = ARG(0, EXWebGLClass);
1084 auto str = ARG(1, std::string);
1085 ctx->addToNextBatch([=, str{std::move(str)}] {
1086 const char *cstr = str.c_str();
1087 glShaderSource(ctx->lookupObject(fShader), 1, &cstr, nullptr);
1088 });
1089 return nullptr;
1090 }
1091
NATIVE_METHOD(useProgram)1092 NATIVE_METHOD(useProgram) {
1093 CTX();
1094 auto program = ARG(0, EXWebGLClass);
1095 ctx->addToNextBatch([=] { glUseProgram(ctx->lookupObject(program)); });
1096 return nullptr;
1097 }
1098
NATIVE_METHOD(validateProgram)1099 NATIVE_METHOD(validateProgram) {
1100 CTX();
1101 auto program = ARG(0, EXWebGLClass);
1102 ctx->addToNextBatch([=] { glValidateProgram(ctx->lookupObject(program)); });
1103 return nullptr;
1104 }
1105
1106 // Programs and shaders (WebGL2)
1107
NATIVE_METHOD(getFragDataLocation)1108 NATIVE_METHOD(getFragDataLocation) {
1109 CTX();
1110 auto program = ARG(0, EXWebGLClass);
1111 auto name = ARG(1, std::string);
1112 GLint location;
1113 ctx->addBlockingToNextBatch(
1114 [&] { location = glGetFragDataLocation(ctx->lookupObject(program), name.c_str()); });
1115 return location == -1 ? jsi::Value::null() : jsi::Value(location);
1116 }
1117
1118 // Uniforms and attributes
1119 // -----------------------
1120
1121 SIMPLE_NATIVE_METHOD(disableVertexAttribArray, glDisableVertexAttribArray); // index
1122
1123 SIMPLE_NATIVE_METHOD(enableVertexAttribArray, glEnableVertexAttribArray); // index
1124
NATIVE_METHOD(getActiveAttrib)1125 NATIVE_METHOD(getActiveAttrib) {
1126 CTX();
1127 return exglGetActiveInfo(
1128 ctx,
1129 runtime,
1130 ARG(0, EXWebGLClass),
1131 ARG(1, GLuint),
1132 GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
1133 glGetActiveAttrib);
1134 }
1135
NATIVE_METHOD(getActiveUniform)1136 NATIVE_METHOD(getActiveUniform) {
1137 CTX();
1138 return exglGetActiveInfo(
1139 ctx,
1140 runtime,
1141 ARG(0, EXWebGLClass),
1142 ARG(1, GLuint),
1143 GL_ACTIVE_UNIFORM_MAX_LENGTH,
1144 glGetActiveUniform);
1145 }
1146
NATIVE_METHOD(getAttribLocation)1147 NATIVE_METHOD(getAttribLocation) {
1148 CTX();
1149 auto program = ARG(0, EXWebGLClass);
1150 auto name = ARG(1, std::string);
1151 GLint location;
1152 ctx->addBlockingToNextBatch(
1153 [&] { location = glGetAttribLocation(ctx->lookupObject(program), name.c_str()); });
1154 return jsi::Value(location);
1155 }
1156
1157 UNIMPL_NATIVE_METHOD(getUniform)
1158
NATIVE_METHOD(getUniformLocation)1159 NATIVE_METHOD(getUniformLocation) {
1160 CTX();
1161 auto program = ARG(0, EXWebGLClass);
1162 auto name = ARG(1, std::string);
1163 GLint location;
1164 ctx->addBlockingToNextBatch(
1165 [&] { location = glGetUniformLocation(ctx->lookupObject(program), name.c_str()); });
1166 return location == -1
1167 ? jsi::Value::null()
1168 : createWebGLObject(runtime, EXWebGLClass::WebGLUniformLocation, {location});
1169 }
1170
1171 UNIMPL_NATIVE_METHOD(getVertexAttrib)
1172
UNIMPL_NATIVE_METHOD(getVertexAttribOffset)1173 UNIMPL_NATIVE_METHOD(getVertexAttribOffset)
1174
1175 NATIVE_METHOD(uniform1f) {
1176 CTX();
1177 auto uniform = ARG(0, EXWebGLClass);
1178 auto x = ARG(1, GLfloat);
1179 ctx->addToNextBatch([uniform, x]() { glUniform1f(uniform, x); });
1180 return nullptr;
1181 }
1182
NATIVE_METHOD(uniform2f)1183 NATIVE_METHOD(uniform2f) {
1184 CTX();
1185 auto uniform = ARG(0, EXWebGLClass);
1186 auto x = ARG(1, GLfloat);
1187 auto y = ARG(2, GLfloat);
1188 ctx->addToNextBatch([uniform, x, y]() { glUniform2f(uniform, x, y); });
1189 return nullptr;
1190 }
1191
NATIVE_METHOD(uniform3f)1192 NATIVE_METHOD(uniform3f) {
1193 CTX();
1194 auto uniform = ARG(0, EXWebGLClass);
1195 auto x = ARG(1, GLfloat);
1196 auto y = ARG(2, GLfloat);
1197 auto z = ARG(3, GLfloat);
1198 ctx->addToNextBatch([uniform, x, y, z]() { glUniform3f(uniform, x, y, z); });
1199 return nullptr;
1200 }
1201
NATIVE_METHOD(uniform4f)1202 NATIVE_METHOD(uniform4f) {
1203 CTX();
1204 auto uniform = ARG(0, EXWebGLClass);
1205 auto x = ARG(1, GLfloat);
1206 auto y = ARG(2, GLfloat);
1207 auto z = ARG(3, GLfloat);
1208 auto w = ARG(4, GLfloat);
1209 ctx->addToNextBatch([uniform, x, y, z, w]() { glUniform4f(uniform, x, y, z, w); });
1210 return nullptr;
1211 }
1212
NATIVE_METHOD(uniform1i)1213 NATIVE_METHOD(uniform1i) {
1214 CTX();
1215 auto uniform = ARG(0, EXWebGLClass);
1216 auto x = ARG(1, GLint);
1217 ctx->addToNextBatch([uniform, x]() { glUniform1i(uniform, x); });
1218 return nullptr;
1219 }
1220
NATIVE_METHOD(uniform2i)1221 NATIVE_METHOD(uniform2i) {
1222 CTX();
1223 auto uniform = ARG(0, EXWebGLClass);
1224 auto x = ARG(1, GLint);
1225 auto y = ARG(2, GLint);
1226 ctx->addToNextBatch([uniform, x, y]() { glUniform2i(uniform, x, y); });
1227 return nullptr;
1228 }
1229
NATIVE_METHOD(uniform3i)1230 NATIVE_METHOD(uniform3i) {
1231 CTX();
1232 auto uniform = ARG(0, EXWebGLClass);
1233 auto x = ARG(1, GLint);
1234 auto y = ARG(2, GLint);
1235 auto z = ARG(3, GLint);
1236 ctx->addToNextBatch([uniform, x, y, z]() { glUniform3i(uniform, x, y, z); });
1237 return nullptr;
1238 }
1239
NATIVE_METHOD(uniform4i)1240 NATIVE_METHOD(uniform4i) {
1241 CTX();
1242 auto uniform = ARG(0, EXWebGLClass);
1243 auto x = ARG(1, GLint);
1244 auto y = ARG(2, GLint);
1245 auto z = ARG(3, GLint);
1246 auto w = ARG(4, GLint);
1247 ctx->addToNextBatch([uniform, x, y, z, w]() { glUniform4i(uniform, x, y, z, w); });
1248 return nullptr;
1249 }
1250
NATIVE_METHOD(uniform1fv)1251 NATIVE_METHOD(uniform1fv) {
1252 CTX();
1253 return exglUniformv(ctx, glUniform1fv, ARG(0, EXWebGLClass), 1, ARG(1, std::vector<float>));
1254 };
1255
NATIVE_METHOD(uniform2fv)1256 NATIVE_METHOD(uniform2fv) {
1257 CTX();
1258 return exglUniformv(ctx, glUniform2fv, ARG(0, EXWebGLClass), 2, ARG(1, std::vector<float>));
1259 };
1260
NATIVE_METHOD(uniform3fv)1261 NATIVE_METHOD(uniform3fv) {
1262 CTX();
1263 return exglUniformv(ctx, glUniform3fv, ARG(0, EXWebGLClass), 3, ARG(1, std::vector<float>));
1264 };
1265
NATIVE_METHOD(uniform4fv)1266 NATIVE_METHOD(uniform4fv) {
1267 CTX();
1268 return exglUniformv(ctx, glUniform4fv, ARG(0, EXWebGLClass), 4, ARG(1, std::vector<float>));
1269 };
1270
NATIVE_METHOD(uniform1iv)1271 NATIVE_METHOD(uniform1iv) {
1272 CTX();
1273 return exglUniformv(ctx, glUniform1iv, ARG(0, EXWebGLClass), 1, ARG(1, std::vector<int32_t>));
1274 };
1275
NATIVE_METHOD(uniform2iv)1276 NATIVE_METHOD(uniform2iv) {
1277 CTX();
1278 return exglUniformv(ctx, glUniform2iv, ARG(0, EXWebGLClass), 2, ARG(1, std::vector<int32_t>));
1279 };
1280
NATIVE_METHOD(uniform3iv)1281 NATIVE_METHOD(uniform3iv) {
1282 CTX();
1283 return exglUniformv(ctx, glUniform3iv, ARG(0, EXWebGLClass), 3, ARG(1, std::vector<int32_t>));
1284 };
1285
NATIVE_METHOD(uniform4iv)1286 NATIVE_METHOD(uniform4iv) {
1287 CTX();
1288 return exglUniformv(ctx, glUniform4iv, ARG(0, EXWebGLClass), 4, ARG(1, std::vector<int32_t>));
1289 };
1290
NATIVE_METHOD(uniformMatrix2fv)1291 NATIVE_METHOD(uniformMatrix2fv) {
1292 CTX();
1293 return exglUniformMatrixv(
1294 ctx,
1295 glUniformMatrix2fv,
1296 ARG(0, EXWebGLClass),
1297 ARG(1, GLboolean),
1298 4,
1299 ARG(2, std::vector<float>));
1300 }
1301
NATIVE_METHOD(uniformMatrix3fv)1302 NATIVE_METHOD(uniformMatrix3fv) {
1303 CTX();
1304 return exglUniformMatrixv(
1305 ctx,
1306 glUniformMatrix3fv,
1307 ARG(0, EXWebGLClass),
1308 ARG(1, GLboolean),
1309 9,
1310 ARG(2, std::vector<float>));
1311 }
1312
NATIVE_METHOD(uniformMatrix4fv)1313 NATIVE_METHOD(uniformMatrix4fv) {
1314 CTX();
1315 return exglUniformMatrixv(
1316 ctx,
1317 glUniformMatrix4fv,
1318 ARG(0, EXWebGLClass),
1319 ARG(1, GLboolean),
1320 16,
1321 ARG(2, std::vector<float>));
1322 }
1323
NATIVE_METHOD(vertexAttrib1fv)1324 NATIVE_METHOD(vertexAttrib1fv) {
1325 CTX();
1326 return exglVertexAttribv(
1327 ctx, glVertexAttrib1fv, ARG(0, EXWebGLClass), ARG(1, std::vector<float>));
1328 }
1329
NATIVE_METHOD(vertexAttrib2fv)1330 NATIVE_METHOD(vertexAttrib2fv) {
1331 CTX();
1332 return exglVertexAttribv(
1333 ctx, glVertexAttrib2fv, ARG(0, EXWebGLClass), ARG(1, std::vector<float>));
1334 }
1335
NATIVE_METHOD(vertexAttrib3fv)1336 NATIVE_METHOD(vertexAttrib3fv) {
1337 CTX();
1338 return exglVertexAttribv(
1339 ctx, glVertexAttrib3fv, ARG(0, EXWebGLClass), ARG(1, std::vector<float>));
1340 }
1341
NATIVE_METHOD(vertexAttrib4fv)1342 NATIVE_METHOD(vertexAttrib4fv) {
1343 CTX();
1344 return exglVertexAttribv(
1345 ctx, glVertexAttrib4fv, ARG(0, EXWebGLClass), ARG(1, std::vector<float>));
1346 }
1347
1348 SIMPLE_NATIVE_METHOD(vertexAttrib1f, glVertexAttrib1f); // index, x
1349 SIMPLE_NATIVE_METHOD(vertexAttrib2f, glVertexAttrib2f); // index, x, y
1350 SIMPLE_NATIVE_METHOD(vertexAttrib3f, glVertexAttrib3f); // index, x, y, z
1351 SIMPLE_NATIVE_METHOD(vertexAttrib4f, glVertexAttrib4f); // index, x, y, z, w
1352
1353 SIMPLE_NATIVE_METHOD(
1354 vertexAttribPointer,
1355 glVertexAttribPointer); // index, itemSize, type, normalized, stride, const void *
1356
1357 // Uniforms and attributes (WebGL2)
1358 // --------------------------------
1359
NATIVE_METHOD(uniform1ui)1360 NATIVE_METHOD(uniform1ui) {
1361 CTX();
1362 auto uniform = ARG(0, EXWebGLClass);
1363 auto x = ARG(1, GLuint);
1364 ctx->addToNextBatch([uniform, x]() { glUniform1ui(uniform, x); });
1365 return nullptr;
1366 }
1367
NATIVE_METHOD(uniform2ui)1368 NATIVE_METHOD(uniform2ui) {
1369 CTX();
1370 auto uniform = ARG(0, EXWebGLClass);
1371 auto x = ARG(1, GLuint);
1372 auto y = ARG(2, GLuint);
1373 ctx->addToNextBatch([uniform, x, y]() { glUniform2ui(uniform, x, y); });
1374 return nullptr;
1375 }
1376
NATIVE_METHOD(uniform3ui)1377 NATIVE_METHOD(uniform3ui) {
1378 CTX();
1379 auto uniform = ARG(0, EXWebGLClass);
1380 auto x = ARG(1, GLuint);
1381 auto y = ARG(2, GLuint);
1382 auto z = ARG(3, GLuint);
1383 ctx->addToNextBatch([uniform, x, y, z]() { glUniform3ui(uniform, x, y, z); });
1384 return nullptr;
1385 }
1386
NATIVE_METHOD(uniform4ui)1387 NATIVE_METHOD(uniform4ui) {
1388 CTX();
1389 auto uniform = ARG(0, EXWebGLClass);
1390 auto x = ARG(1, GLuint);
1391 auto y = ARG(2, GLuint);
1392 auto z = ARG(3, GLuint);
1393 auto w = ARG(4, GLuint);
1394 ctx->addToNextBatch([uniform, x, y, z, w]() { glUniform4ui(uniform, x, y, z, w); });
1395 return nullptr;
1396 }
1397
NATIVE_METHOD(uniform1uiv)1398 NATIVE_METHOD(uniform1uiv) {
1399 CTX();
1400 return exglUniformv(ctx, glUniform1uiv, ARG(0, EXWebGLClass), 1, ARG(1, std::vector<uint32_t>));
1401 };
1402
NATIVE_METHOD(uniform2uiv)1403 NATIVE_METHOD(uniform2uiv) {
1404 CTX();
1405 return exglUniformv(ctx, glUniform2uiv, ARG(0, EXWebGLClass), 2, ARG(1, std::vector<uint32_t>));
1406 };
1407
NATIVE_METHOD(uniform3uiv)1408 NATIVE_METHOD(uniform3uiv) {
1409 CTX();
1410 return exglUniformv(ctx, glUniform3uiv, ARG(0, EXWebGLClass), 3, ARG(1, std::vector<uint32_t>));
1411 };
1412
NATIVE_METHOD(uniform4uiv)1413 NATIVE_METHOD(uniform4uiv) {
1414 CTX();
1415 return exglUniformv(ctx, glUniform4uiv, ARG(0, EXWebGLClass), 4, ARG(1, std::vector<uint32_t>));
1416 };
1417
NATIVE_METHOD(uniformMatrix3x2fv)1418 NATIVE_METHOD(uniformMatrix3x2fv) {
1419 CTX();
1420 return exglUniformMatrixv(
1421 ctx,
1422 glUniformMatrix3x2fv,
1423 ARG(0, EXWebGLClass),
1424 ARG(1, GLboolean),
1425 6,
1426 ARG(2, std::vector<float>));
1427 }
1428
NATIVE_METHOD(uniformMatrix4x2fv)1429 NATIVE_METHOD(uniformMatrix4x2fv) {
1430 CTX();
1431 return exglUniformMatrixv(
1432 ctx,
1433 glUniformMatrix4x2fv,
1434 ARG(0, EXWebGLClass),
1435 ARG(1, GLboolean),
1436 8,
1437 ARG(2, std::vector<float>));
1438 }
1439
NATIVE_METHOD(uniformMatrix2x3fv)1440 NATIVE_METHOD(uniformMatrix2x3fv) {
1441 CTX();
1442 return exglUniformMatrixv(
1443 ctx,
1444 glUniformMatrix2x3fv,
1445 ARG(0, EXWebGLClass),
1446 ARG(1, GLboolean),
1447 6,
1448 ARG(2, std::vector<float>));
1449 }
1450
NATIVE_METHOD(uniformMatrix4x3fv)1451 NATIVE_METHOD(uniformMatrix4x3fv) {
1452 CTX();
1453 return exglUniformMatrixv(
1454 ctx,
1455 glUniformMatrix4x3fv,
1456 ARG(0, EXWebGLClass),
1457 ARG(1, GLboolean),
1458 12,
1459 ARG(2, std::vector<float>));
1460 }
1461
NATIVE_METHOD(uniformMatrix2x4fv)1462 NATIVE_METHOD(uniformMatrix2x4fv) {
1463 CTX();
1464 return exglUniformMatrixv(
1465 ctx,
1466 glUniformMatrix2x4fv,
1467 ARG(0, EXWebGLClass),
1468 ARG(1, GLboolean),
1469 8,
1470 ARG(2, std::vector<float>));
1471 }
1472
NATIVE_METHOD(uniformMatrix3x4fv)1473 NATIVE_METHOD(uniformMatrix3x4fv) {
1474 CTX();
1475 return exglUniformMatrixv(
1476 ctx,
1477 glUniformMatrix3x4fv,
1478 ARG(0, EXWebGLClass),
1479 ARG(1, GLboolean),
1480 12,
1481 ARG(2, std::vector<float>));
1482 }
1483
1484 SIMPLE_NATIVE_METHOD(vertexAttribI4i, glVertexAttribI4i); // index, x, y, z, w
1485 SIMPLE_NATIVE_METHOD(vertexAttribI4ui, glVertexAttribI4ui); // index, x, y, z, w
1486
NATIVE_METHOD(vertexAttribI4iv)1487 NATIVE_METHOD(vertexAttribI4iv) {
1488 CTX();
1489 return exglVertexAttribv(ctx, glVertexAttribI4iv, ARG(0, GLuint), ARG(1, std::vector<int32_t>));
1490 }
1491
NATIVE_METHOD(vertexAttribI4uiv)1492 NATIVE_METHOD(vertexAttribI4uiv) {
1493 CTX();
1494 return exglVertexAttribv(ctx, glVertexAttribI4uiv, ARG(0, GLuint), ARG(1, std::vector<uint32_t>));
1495 }
1496
1497 SIMPLE_NATIVE_METHOD(
1498 vertexAttribIPointer,
1499 glVertexAttribIPointer); // index, size, type, stride, offset
1500
1501 // Drawing buffers
1502 // ---------------
1503
1504 SIMPLE_NATIVE_METHOD(clear, glClear); // mask
1505
1506 SIMPLE_NATIVE_METHOD(drawArrays, glDrawArrays); // mode, first, count)
1507
1508 SIMPLE_NATIVE_METHOD(drawElements, glDrawElements); // mode, count, type, offset
1509
1510 SIMPLE_NATIVE_METHOD(finish, glFinish);
1511
1512 SIMPLE_NATIVE_METHOD(flush, glFlush);
1513
1514 // Drawing buffers (WebGL2)
1515 // ------------------------
1516
1517 SIMPLE_NATIVE_METHOD(vertexAttribDivisor, glVertexAttribDivisor); // index, divisor
1518
1519 SIMPLE_NATIVE_METHOD(
1520 drawArraysInstanced,
1521 glDrawArraysInstanced); // mode, first, count, instancecount
1522
1523 SIMPLE_NATIVE_METHOD(
1524 drawElementsInstanced,
1525 glDrawElementsInstanced); // mode, count, type, offset, instanceCount
1526
1527 SIMPLE_NATIVE_METHOD(
1528 drawRangeElements,
1529 glDrawRangeElements); // mode, start, end, count, type, offset
1530
NATIVE_METHOD(drawBuffers)1531 NATIVE_METHOD(drawBuffers) {
1532 CTX();
1533 auto data = jsArrayToVector<GLenum>(runtime, ARG(0, jsi::Array));
1534 ctx->addToNextBatch(
1535 [data{std::move(data)}] { glDrawBuffers(static_cast<GLsizei>(data.size()), data.data()); });
1536 return nullptr;
1537 }
1538
NATIVE_METHOD(clearBufferfv)1539 NATIVE_METHOD(clearBufferfv) {
1540 CTX();
1541 auto buffer = ARG(0, GLenum);
1542 auto drawbuffer = ARG(1, GLint);
1543 auto values = ARG(2, TypedArrayKind::Float32Array).toVector(runtime);
1544 ctx->addToNextBatch(
1545 [=, values{std::move(values)}] { glClearBufferfv(buffer, drawbuffer, values.data()); });
1546 return nullptr;
1547 }
1548
NATIVE_METHOD(clearBufferiv)1549 NATIVE_METHOD(clearBufferiv) {
1550 CTX();
1551 auto buffer = ARG(0, GLenum);
1552 auto drawbuffer = ARG(1, GLint);
1553 auto values = ARG(2, TypedArrayKind::Int32Array).toVector(runtime);
1554 ctx->addToNextBatch(
1555 [=, values{std::move(values)}] { glClearBufferiv(buffer, drawbuffer, values.data()); });
1556 return nullptr;
1557 }
1558
NATIVE_METHOD(clearBufferuiv)1559 NATIVE_METHOD(clearBufferuiv) {
1560 CTX();
1561 auto buffer = ARG(0, GLenum);
1562 auto drawbuffer = ARG(1, GLint);
1563 auto values = ARG(2, TypedArrayKind::Uint32Array).toVector(runtime);
1564 ctx->addToNextBatch(
1565 [=, values{std::move(values)}] { glClearBufferuiv(buffer, drawbuffer, values.data()); });
1566 return nullptr;
1567 }
1568
1569 SIMPLE_NATIVE_METHOD(clearBufferfi, glClearBufferfi); // buffer, drawbuffer, depth, stencil
1570
1571 // Query objects (WebGL2)
1572 // ----------------------
1573
NATIVE_METHOD(createQuery)1574 NATIVE_METHOD(createQuery) {
1575 CTX();
1576 return exglGenObject(ctx, runtime, glGenQueries, EXWebGLClass::WebGLQuery);
1577 }
1578
NATIVE_METHOD(deleteQuery)1579 NATIVE_METHOD(deleteQuery) {
1580 CTX();
1581 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteQueries);
1582 }
1583
NATIVE_METHOD(isQuery)1584 NATIVE_METHOD(isQuery) {
1585 CTX();
1586 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsQuery);
1587 }
1588
NATIVE_METHOD(beginQuery)1589 NATIVE_METHOD(beginQuery) {
1590 CTX();
1591 auto target = ARG(0, GLenum);
1592 auto query = ARG(1, EXWebGLClass);
1593 ctx->addToNextBatch([=] { glBeginQuery(target, ctx->lookupObject(query)); });
1594 return nullptr;
1595 }
1596
1597 SIMPLE_NATIVE_METHOD(endQuery, glEndQuery); // target
1598
NATIVE_METHOD(getQuery)1599 NATIVE_METHOD(getQuery) {
1600 CTX();
1601 auto target = ARG(0, GLenum);
1602 auto pname = ARG(1, GLenum);
1603 GLint params;
1604 ctx->addBlockingToNextBatch([&] { glGetQueryiv(target, pname, ¶ms); });
1605 return params == 0
1606 ? jsi::Value::null()
1607 : createWebGLObject(runtime, EXWebGLClass::WebGLQuery, {static_cast<double>(params)});
1608 }
1609
NATIVE_METHOD(getQueryParameter)1610 NATIVE_METHOD(getQueryParameter) {
1611 CTX();
1612 auto query = ARG(0, EXWebGLClass);
1613 auto pname = ARG(1, GLenum);
1614 GLuint params;
1615 ctx->addBlockingToNextBatch(
1616 [&] { glGetQueryObjectuiv(ctx->lookupObject(query), pname, ¶ms); });
1617 return params == 0 ? jsi::Value::null() : static_cast<double>(params);
1618 }
1619
1620 // Samplers (WebGL2)
1621 // -----------------
1622
NATIVE_METHOD(createSampler)1623 NATIVE_METHOD(createSampler) {
1624 CTX();
1625 return exglGenObject(ctx, runtime, glGenSamplers, EXWebGLClass::WebGLSampler);
1626 }
1627
NATIVE_METHOD(deleteSampler)1628 NATIVE_METHOD(deleteSampler) {
1629 CTX();
1630 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteSamplers);
1631 }
1632
NATIVE_METHOD(bindSampler)1633 NATIVE_METHOD(bindSampler) {
1634 CTX();
1635 auto unit = ARG(0, GLuint);
1636 auto sampler = ARG(1, EXWebGLClass);
1637 ctx->addToNextBatch([=] { glBindSampler(unit, ctx->lookupObject(sampler)); });
1638 return nullptr;
1639 }
1640
NATIVE_METHOD(isSampler)1641 NATIVE_METHOD(isSampler) {
1642 CTX();
1643 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsSampler);
1644 }
1645
NATIVE_METHOD(samplerParameteri)1646 NATIVE_METHOD(samplerParameteri) {
1647 CTX();
1648 auto sampler = ARG(0, EXWebGLClass);
1649 auto pname = ARG(1, GLenum);
1650 auto param = ARG(2, GLfloat);
1651 ctx->addToNextBatch([=] { glSamplerParameteri(ctx->lookupObject(sampler), pname, param); });
1652 return nullptr;
1653 }
1654
NATIVE_METHOD(samplerParameterf)1655 NATIVE_METHOD(samplerParameterf) {
1656 CTX();
1657 auto sampler = ARG(0, EXWebGLClass);
1658 auto pname = ARG(1, GLenum);
1659 auto param = ARG(2, GLfloat);
1660 ctx->addToNextBatch([=] { glSamplerParameterf(ctx->lookupObject(sampler), pname, param); });
1661 return nullptr;
1662 }
1663
NATIVE_METHOD(getSamplerParameter)1664 NATIVE_METHOD(getSamplerParameter) {
1665 CTX();
1666 auto sampler = ARG(0, EXWebGLClass);
1667 auto pname = ARG(1, GLenum);
1668 bool isFloatParam = pname == GL_TEXTURE_MAX_LOD || pname == GL_TEXTURE_MIN_LOD;
1669 union {
1670 GLfloat f;
1671 GLint i;
1672 } param;
1673
1674 ctx->addBlockingToNextBatch([&] {
1675 if (isFloatParam) {
1676 glGetSamplerParameterfv(ctx->lookupObject(sampler), pname, ¶m.f);
1677 } else {
1678 glGetSamplerParameteriv(ctx->lookupObject(sampler), pname, ¶m.i);
1679 }
1680 });
1681 return isFloatParam ? static_cast<double>(param.f) : static_cast<double>(param.i);
1682 }
1683
1684 // Sync objects (WebGL2)
1685 // ---------------------
1686
1687 UNIMPL_NATIVE_METHOD(fenceSync)
1688
UNIMPL_NATIVE_METHOD(isSync)1689 UNIMPL_NATIVE_METHOD(isSync)
1690
1691 UNIMPL_NATIVE_METHOD(deleteSync)
1692
1693 UNIMPL_NATIVE_METHOD(clientWaitSync)
1694
1695 UNIMPL_NATIVE_METHOD(waitSync)
1696
1697 UNIMPL_NATIVE_METHOD(getSyncParameter)
1698
1699 // Transform feedback (WebGL2)
1700 // ---------------------------
1701
1702 NATIVE_METHOD(createTransformFeedback) {
1703 CTX();
1704 return exglGenObject(ctx, runtime, glGenTransformFeedbacks, EXWebGLClass::WebGLTransformFeedback);
1705 }
1706
NATIVE_METHOD(deleteTransformFeedback)1707 NATIVE_METHOD(deleteTransformFeedback) {
1708 CTX();
1709 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteTransformFeedbacks);
1710 }
1711
NATIVE_METHOD(isTransformFeedback)1712 NATIVE_METHOD(isTransformFeedback) {
1713 CTX();
1714 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsTransformFeedback);
1715 }
1716
NATIVE_METHOD(bindTransformFeedback)1717 NATIVE_METHOD(bindTransformFeedback) {
1718 CTX();
1719 auto target = ARG(0, GLenum);
1720 auto transformFeedback = ARG(1, EXWebGLClass);
1721 ctx->addToNextBatch(
1722 [=] { glBindTransformFeedback(target, ctx->lookupObject(transformFeedback)); });
1723 return nullptr;
1724 }
1725
1726 SIMPLE_NATIVE_METHOD(beginTransformFeedback, glBeginTransformFeedback); // primitiveMode
1727
1728 SIMPLE_NATIVE_METHOD(endTransformFeedback, glEndTransformFeedback);
1729
NATIVE_METHOD(transformFeedbackVaryings)1730 NATIVE_METHOD(transformFeedbackVaryings) {
1731 CTX();
1732 auto program = ARG(0, EXWebGLClass);
1733 std::vector<std::string> varyings = jsArrayToVector<std::string>(runtime, ARG(1, jsi::Array));
1734 auto bufferMode = ARG(2, GLenum);
1735
1736 ctx->addToNextBatch([=, varyings{std::move(varyings)}] {
1737 std::vector<const char *> varyingsRaw(varyings.size());
1738 std::transform(
1739 varyings.begin(), varyings.end(), varyingsRaw.begin(), [](const std::string &str) {
1740 return str.c_str();
1741 });
1742
1743 glTransformFeedbackVaryings(
1744 ctx->lookupObject(program),
1745 static_cast<GLsizei>(varyingsRaw.size()),
1746 varyingsRaw.data(),
1747 bufferMode);
1748 });
1749 return nullptr;
1750 }
1751
NATIVE_METHOD(getTransformFeedbackVarying)1752 NATIVE_METHOD(getTransformFeedbackVarying) {
1753 CTX();
1754 return exglGetActiveInfo(
1755 ctx,
1756 runtime,
1757 ARG(0, EXWebGLClass),
1758 ARG(1, GLuint),
1759 GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH,
1760 glGetTransformFeedbackVarying);
1761 }
1762
1763 SIMPLE_NATIVE_METHOD(pauseTransformFeedback, glPauseTransformFeedback);
1764
1765 SIMPLE_NATIVE_METHOD(resumeTransformFeedback, glResumeTransformFeedback);
1766
1767 // Uniform buffer objects (WebGL2)
1768 // -------------------------------
1769
NATIVE_METHOD(bindBufferBase)1770 NATIVE_METHOD(bindBufferBase) {
1771 CTX();
1772 auto target = ARG(0, GLenum);
1773 auto index = ARG(1, GLuint);
1774 auto buffer = ARG(2, EXWebGLClass);
1775 ctx->addToNextBatch([=] { glBindBufferBase(target, index, ctx->lookupObject(buffer)); });
1776 return nullptr;
1777 }
1778
NATIVE_METHOD(bindBufferRange)1779 NATIVE_METHOD(bindBufferRange) {
1780 CTX();
1781 auto target = ARG(0, GLenum);
1782 auto index = ARG(1, GLuint);
1783 auto buffer = ARG(2, EXWebGLClass);
1784 auto offset = ARG(3, GLint);
1785 auto size = ARG(4, GLsizei);
1786 ctx->addToNextBatch(
1787 [=] { glBindBufferRange(target, index, ctx->lookupObject(buffer), offset, size); });
1788 return nullptr;
1789 }
1790
NATIVE_METHOD(getUniformIndices)1791 NATIVE_METHOD(getUniformIndices) {
1792 CTX();
1793 auto program = ARG(0, EXWebGLClass);
1794 std::vector<std::string> uniformNames = jsArrayToVector<std::string>(runtime, ARG(1, jsi::Array));
1795
1796 std::vector<const char *> uniformNamesRaw(uniformNames.size());
1797 std::transform(
1798 uniformNames.begin(),
1799 uniformNames.end(),
1800 uniformNamesRaw.begin(),
1801 [](const std::string &str) { return str.c_str(); });
1802
1803 std::vector<GLuint> indices(uniformNames.size());
1804 ctx->addBlockingToNextBatch([&] {
1805 glGetUniformIndices(
1806 ctx->lookupObject(program),
1807 static_cast<GLsizei>(uniformNames.size()),
1808 uniformNamesRaw.data(),
1809 &indices[0]);
1810 });
1811 jsi::Array jsResult(runtime, indices.size());
1812 for (unsigned int i = 0; i < indices.size(); i++) {
1813 jsResult.setValueAtIndex(runtime, i, static_cast<double>(indices[i]));
1814 }
1815 return jsResult;
1816 }
1817
NATIVE_METHOD(getActiveUniforms)1818 NATIVE_METHOD(getActiveUniforms) {
1819 CTX();
1820 auto program = ARG(0, EXWebGLClass);
1821 auto uniformIndices = jsArrayToVector<GLuint>(runtime, ARG(1, jsi::Array));
1822 auto pname = ARG(2, GLenum);
1823 std::vector<GLint> params(uniformIndices.size());
1824
1825 ctx->addBlockingToNextBatch([&] {
1826 glGetActiveUniformsiv(
1827 ctx->lookupObject(program),
1828 static_cast<GLsizei>(uniformIndices.size()),
1829 uniformIndices.data(),
1830 pname,
1831 ¶ms[0]);
1832 });
1833 jsi::Array jsResult(runtime, params.size());
1834 for (unsigned int i = 0; i < params.size(); i++) {
1835 jsResult.setValueAtIndex(
1836 runtime,
1837 i,
1838 pname == GL_UNIFORM_IS_ROW_MAJOR ? params[i] != 0 : static_cast<double>(params[i]));
1839 }
1840 return jsResult;
1841 }
1842
NATIVE_METHOD(getUniformBlockIndex)1843 NATIVE_METHOD(getUniformBlockIndex) {
1844 CTX();
1845 auto program = ARG(0, EXWebGLClass);
1846 auto uniformBlockName = ARG(1, std::string);
1847
1848 GLuint blockIndex;
1849 ctx->addBlockingToNextBatch([&] {
1850 blockIndex = glGetUniformBlockIndex(ctx->lookupObject(program), uniformBlockName.c_str());
1851 });
1852 return static_cast<double>(blockIndex);
1853 }
1854
1855 UNIMPL_NATIVE_METHOD(getActiveUniformBlockParameter)
1856
NATIVE_METHOD(getActiveUniformBlockName)1857 NATIVE_METHOD(getActiveUniformBlockName) {
1858 CTX();
1859 auto fProgram = ARG(0, EXWebGLClass);
1860 auto uniformBlockIndex = ARG(1, GLuint);
1861
1862 std::string blockName;
1863 ctx->addBlockingToNextBatch([&] {
1864 GLuint program = ctx->lookupObject(fProgram);
1865 GLint bufSize;
1866 glGetActiveUniformBlockiv(program, uniformBlockIndex, GL_UNIFORM_BLOCK_NAME_LENGTH, &bufSize);
1867 blockName.resize(bufSize > 0 ? bufSize - 1 : 0);
1868 glGetActiveUniformBlockName(program, uniformBlockIndex, bufSize, NULL, &blockName[0]);
1869 });
1870 return jsi::String::createFromUtf8(runtime, blockName);
1871 }
1872
NATIVE_METHOD(uniformBlockBinding)1873 NATIVE_METHOD(uniformBlockBinding) {
1874 CTX();
1875 auto program = ARG(0, EXWebGLClass);
1876 auto uniformBlockIndex = ARG(1, GLuint);
1877 auto uniformBlockBinding = ARG(2, GLuint);
1878 ctx->addToNextBatch([=] {
1879 glUniformBlockBinding(ctx->lookupObject(program), uniformBlockIndex, uniformBlockBinding);
1880 });
1881 return nullptr;
1882 }
1883
1884 // Vertex Array Object (WebGL2)
1885 // ----------------------------
1886
NATIVE_METHOD(createVertexArray)1887 NATIVE_METHOD(createVertexArray) {
1888 CTX();
1889 return exglGenObject(ctx, runtime, glGenVertexArrays, EXWebGLClass::WebGLVertexArrayObject);
1890 }
1891
NATIVE_METHOD(deleteVertexArray)1892 NATIVE_METHOD(deleteVertexArray) {
1893 CTX();
1894 return exglDeleteObject(ctx, ARG(0, EXWebGLClass), glDeleteVertexArrays);
1895 }
1896
NATIVE_METHOD(isVertexArray)1897 NATIVE_METHOD(isVertexArray) {
1898 CTX();
1899 return exglIsObject(ctx, ARG(0, EXWebGLClass), glIsVertexArray);
1900 }
1901
NATIVE_METHOD(bindVertexArray)1902 NATIVE_METHOD(bindVertexArray) {
1903 CTX();
1904 auto vertexArray = ARG(0, EXWebGLClass);
1905 ctx->addToNextBatch([=] { glBindVertexArray(ctx->lookupObject(vertexArray)); });
1906 return nullptr;
1907 }
1908
1909 // Extensions
1910 // ----------
1911
1912 // It may return some extensions that are not specified by WebGL specification nor drafts.
NATIVE_METHOD(getSupportedExtensions)1913 NATIVE_METHOD(getSupportedExtensions) {
1914 CTX();
1915 // Set with supported extensions is cached to make checks in `getExtension` faster.
1916 ctx->maybeReadAndCacheSupportedExtensions();
1917
1918 jsi::Array extensions(runtime, ctx->supportedExtensions.size());
1919 int i = 0;
1920 for (auto const &extensionName : ctx->supportedExtensions) {
1921 extensions.setValueAtIndex(runtime, i++, jsi::String::createFromUtf8(runtime, extensionName));
1922 }
1923 return extensions;
1924 }
1925
1926 #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
1927 #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
1928
NATIVE_METHOD(getExtension)1929 NATIVE_METHOD(getExtension) {
1930 CTX();
1931 auto name = ARG(0, std::string);
1932
1933 // There is no `getExtension` equivalent in OpenGL ES so return `null`
1934 // if requested extension is not returned by `getSupportedExtensions`.
1935 ctx->maybeReadAndCacheSupportedExtensions();
1936 if (ctx->supportedExtensions.find(name) == ctx->supportedExtensions.end()) {
1937 return nullptr;
1938 }
1939
1940 if (name == "EXT_texture_filter_anisotropic") {
1941 jsi::Object result(runtime);
1942 result.setProperty(
1943 runtime, "TEXTURE_MAX_ANISOTROPY_EXT", jsi::Value(GL_TEXTURE_MAX_ANISOTROPY_EXT));
1944 result.setProperty(
1945 runtime, "MAX_TEXTURE_MAX_ANISOTROPY_EXT", jsi::Value(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT));
1946 return result;
1947 }
1948 return jsi::Object(runtime);
1949 }
1950
1951 // Exponent extensions
1952 // -------------------
1953
NATIVE_METHOD(endFrameEXP)1954 NATIVE_METHOD(endFrameEXP) {
1955 CTX();
1956 ctx->addToNextBatch([=] { ctx->needsRedraw = true; });
1957 ctx->endNextBatch();
1958 ctx->flushOnGLThread();
1959 return nullptr;
1960 }
1961
NATIVE_METHOD(flushEXP)1962 NATIVE_METHOD(flushEXP) {
1963 CTX();
1964 // nothing, it's just a helper so that we can measure how much time some operations take
1965 ctx->addBlockingToNextBatch([&] {});
1966 return nullptr;
1967 }
1968
1969 } // namespace method
1970 } // namespace gl_cpp
1971 } // namespace expo
1972