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