@geastack/native-webgl-angle 0.1.12 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/geatsc-plugin-readback.mjs +21 -0
- package/geatsc-plugin-uniforms.mjs +214 -59
- package/geatsc-plugin-uploads.mjs +7 -2
- package/geatsc-plugin.mjs +912 -67
- package/native/angle_webgl_host.mm +217 -22
- package/package.json +1 -1
- package/src/inflate.ts +1 -1
- package/src/nativeWebGL.ts +67 -13
- package/src/nativeWebGLHost.ts +19 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#include "webgl_readback.h"
|
|
2
|
+
// GEA_WEBGL_STATIC_GLES: EGL/GLES are statically linked into the program, so
|
|
3
|
+
// nothing is loaded and entry points resolve through eglGetProcAddress.
|
|
2
4
|
#if defined(_WIN32)
|
|
3
5
|
#ifndef NOMINMAX
|
|
4
6
|
#define NOMINMAX
|
|
@@ -7,13 +9,14 @@
|
|
|
7
9
|
// Legacy Win16 macros are not C++ identifiers and must not leak into the runtime.
|
|
8
10
|
#undef near
|
|
9
11
|
#undef far
|
|
10
|
-
#
|
|
12
|
+
#elif defined(__APPLE__)
|
|
11
13
|
#include "gea/apple/native_bridge.h"
|
|
12
14
|
|
|
13
15
|
#import <AppKit/AppKit.h>
|
|
14
16
|
#import <QuartzCore/QuartzCore.h>
|
|
15
17
|
#import <dispatch/dispatch.h>
|
|
16
|
-
|
|
18
|
+
#endif
|
|
19
|
+
#if !defined(_WIN32) && !defined(GEA_WEBGL_STATIC_GLES)
|
|
17
20
|
#include <dlfcn.h>
|
|
18
21
|
#endif
|
|
19
22
|
// Typed uniform arguments use the compiler runtime on both native platforms.
|
|
@@ -172,7 +175,7 @@ extern "C" bool gea_three_key_pressed(double code) {
|
|
|
172
175
|
return gGeaKeyState[c];
|
|
173
176
|
}
|
|
174
177
|
|
|
175
|
-
#if defined(
|
|
178
|
+
#if !defined(__APPLE__)
|
|
176
179
|
// The Win32 window procedure owns input on Windows; it reports into the same
|
|
177
180
|
// tables the AppKit host view fills on macOS (keys as macOS virtual key codes).
|
|
178
181
|
extern "C" void gea_three_set_key_state(int code, bool down) {
|
|
@@ -189,7 +192,7 @@ extern "C" void gea_three_set_pointer_state(double x, double y, double width, do
|
|
|
189
192
|
}
|
|
190
193
|
#endif
|
|
191
194
|
|
|
192
|
-
#if
|
|
195
|
+
#if defined(__APPLE__)
|
|
193
196
|
@interface GeaAngleWebGLHostView : NSView
|
|
194
197
|
@end
|
|
195
198
|
|
|
@@ -410,6 +413,10 @@ using PFNGLTEXIMAGE2DPROC = void (*)(GLenum, GLint, GLint, GLsizei, GLsizei, GLi
|
|
|
410
413
|
using PFNGLTEXPARAMETERFPROC = void (*)(GLenum, GLenum, GLfloat);
|
|
411
414
|
using PFNGLTEXPARAMETERIPROC = void (*)(GLenum, GLenum, GLint);
|
|
412
415
|
using PFNGLTEXSUBIMAGE2DPROC = void (*)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void *);
|
|
416
|
+
using PFNGLTEXIMAGE3DPROC = void (*)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const void *);
|
|
417
|
+
using PFNGLTEXSUBIMAGE3DPROC = void (*)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const void *);
|
|
418
|
+
using PFNGLTEXSTORAGE3DPROC = void (*)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei);
|
|
419
|
+
using PFNGLFRAMEBUFFERTEXTURELAYERPROC = void (*)(GLenum, GLenum, GLuint, GLint, GLint);
|
|
413
420
|
using PFNGLTEXSTORAGE2DPROC = void (*)(GLenum, GLsizei, GLenum, GLsizei, GLsizei);
|
|
414
421
|
using PFNGLUNIFORM1FPROC = void (*)(GLint, GLfloat);
|
|
415
422
|
using PFNGLUNIFORM1FVPROC = void (*)(GLint, GLsizei, const GLfloat *);
|
|
@@ -447,6 +454,13 @@ using PFNGLCOPYTEXIMAGE2DPROC=void(*)(GLenum,GLint,GLenum,GLint,GLint,GLsizei,GL
|
|
|
447
454
|
using PFNGLCOPYTEXSUBIMAGE2DPROC=void(*)(GLenum,GLint,GLint,GLint,GLint,GLint,GLsizei,GLsizei);
|
|
448
455
|
using PFNGLBLITFRAMEBUFFERPROC = void (*)(GLint,GLint,GLint,GLint,GLint,GLint,GLint,GLint,GLbitfield,GLenum);
|
|
449
456
|
using PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC = void (*)(GLenum,GLsizei,GLenum,GLsizei,GLsizei);
|
|
457
|
+
using GLuint64 = std::uint64_t;
|
|
458
|
+
using GLsync = struct __GLsync *;
|
|
459
|
+
using PFNGLMAPBUFFERRANGEPROC = void *(*)(GLenum, GLintptr, GLsizeiptr, GLbitfield);
|
|
460
|
+
using PFNGLUNMAPBUFFERPROC = GLboolean (*)(GLenum);
|
|
461
|
+
using PFNGLFENCESYNCPROC = GLsync (*)(GLenum, GLbitfield);
|
|
462
|
+
using PFNGLCLIENTWAITSYNCPROC = GLenum (*)(GLsync, GLbitfield, GLuint64);
|
|
463
|
+
using PFNGLDELETESYNCPROC = void (*)(GLsync);
|
|
450
464
|
struct AngleWebGLState {
|
|
451
465
|
PFNGLCOPYTEXIMAGE2DPROC glCopyTexImage2D=nullptr;
|
|
452
466
|
PFNGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D=nullptr;
|
|
@@ -533,6 +547,12 @@ struct AngleWebGLState {
|
|
|
533
547
|
PFNGLPIXELSTOREIPROC glPixelStorei = nullptr;
|
|
534
548
|
PFNGLPOLYGONOFFSETPROC glPolygonOffset = nullptr;
|
|
535
549
|
PFNGLREADPIXELSPROC glReadPixels = nullptr;
|
|
550
|
+
// WebGL2 asynchronous readback: PIXEL_PACK_BUFFER reads, sync objects and read-mapping.
|
|
551
|
+
PFNGLMAPBUFFERRANGEPROC glMapBufferRange = nullptr;
|
|
552
|
+
PFNGLUNMAPBUFFERPROC glUnmapBuffer = nullptr;
|
|
553
|
+
PFNGLFENCESYNCPROC glFenceSync = nullptr;
|
|
554
|
+
PFNGLCLIENTWAITSYNCPROC glClientWaitSync = nullptr;
|
|
555
|
+
PFNGLDELETESYNCPROC glDeleteSync = nullptr;
|
|
536
556
|
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr;
|
|
537
557
|
PFNGLSCISSORPROC glScissor = nullptr;
|
|
538
558
|
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
|
|
@@ -547,6 +567,12 @@ struct AngleWebGLState {
|
|
|
547
567
|
PFNGLTEXPARAMETERIPROC glTexParameteri = nullptr;
|
|
548
568
|
PFNGLTEXSUBIMAGE2DPROC glTexSubImage2D = nullptr;
|
|
549
569
|
PFNGLTEXSTORAGE2DPROC glTexStorage2D = nullptr;
|
|
570
|
+
// Array/3D entry points are optional: a GLES without them still starts,
|
|
571
|
+
// and uploads to those targets report GL_INVALID_OPERATION in the log.
|
|
572
|
+
PFNGLTEXIMAGE3DPROC glTexImage3D = nullptr;
|
|
573
|
+
PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D = nullptr;
|
|
574
|
+
PFNGLTEXSTORAGE3DPROC glTexStorage3D = nullptr;
|
|
575
|
+
PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = nullptr;
|
|
550
576
|
PFNGLUNIFORM1FPROC glUniform1f = nullptr;
|
|
551
577
|
PFNGLUNIFORM1FVPROC glUniform1fv = nullptr;
|
|
552
578
|
PFNGLUNIFORM1IPROC glUniform1i = nullptr;
|
|
@@ -579,7 +605,7 @@ struct AngleWebGLState {
|
|
|
579
605
|
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
|
|
580
606
|
PFNGLVIEWPORTPROC glViewport = nullptr;
|
|
581
607
|
|
|
582
|
-
#if defined(
|
|
608
|
+
#if !defined(__APPLE__)
|
|
583
609
|
void *nativeWindow = nullptr;
|
|
584
610
|
#else
|
|
585
611
|
NSView *hostView = nil;
|
|
@@ -617,7 +643,7 @@ static bool nativeShadowColorAuditEnabled() {
|
|
|
617
643
|
}
|
|
618
644
|
|
|
619
645
|
static void smokeLog(const char *format, ...) {
|
|
620
|
-
char message[
|
|
646
|
+
char message[16384] = {};
|
|
621
647
|
va_list args;
|
|
622
648
|
va_start(args, format);
|
|
623
649
|
std::vsnprintf(message, sizeof(message), format, args);
|
|
@@ -631,8 +657,13 @@ static void smokeLog(const char *format, ...) {
|
|
|
631
657
|
std::fprintf(stderr, "%s\n", message);
|
|
632
658
|
return;
|
|
633
659
|
}
|
|
634
|
-
#
|
|
660
|
+
#elif defined(__APPLE__)
|
|
635
661
|
if (!path || path[0] == '\0') path = "/tmp/three-angle-metal-smoke.log";
|
|
662
|
+
#else
|
|
663
|
+
if (!path || path[0] == '\0') {
|
|
664
|
+
std::fprintf(stderr, "%s\n", message);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
636
667
|
#endif
|
|
637
668
|
if (FILE *file = std::fopen(path, "a")) {
|
|
638
669
|
std::fprintf(file, "%s\n", message);
|
|
@@ -653,7 +684,7 @@ extern "C" void gea_three_angle_smoke_log(std::string message) {
|
|
|
653
684
|
// handler records the position in the host view's coordinate space with the
|
|
654
685
|
// same top-left-origin flip the per-view path used. Returning the event
|
|
655
686
|
// unmodified keeps normal dispatch (clicks, first responder) intact.
|
|
656
|
-
#if
|
|
687
|
+
#if defined(__APPLE__)
|
|
657
688
|
static id gGeaPointerMonitor = nil;
|
|
658
689
|
static void geaInstallPointerMonitor(void) {
|
|
659
690
|
if (gGeaPointerMonitor) return;
|
|
@@ -696,9 +727,16 @@ static void *openFirst(const char *envName, const char *const *paths) {
|
|
|
696
727
|
|
|
697
728
|
#endif
|
|
698
729
|
|
|
730
|
+
#if defined(GEA_WEBGL_STATIC_GLES)
|
|
731
|
+
extern "C" void *eglGetProcAddress(const char *name);
|
|
732
|
+
#endif
|
|
699
733
|
template <typename Fn>
|
|
700
734
|
static Fn loadSymbol(void *library, const char *name) {
|
|
701
|
-
#if defined(
|
|
735
|
+
#if defined(GEA_WEBGL_STATIC_GLES)
|
|
736
|
+
(void)library;
|
|
737
|
+
if (std::strcmp(name, "eglGetProcAddress") == 0) return reinterpret_cast<Fn>(&eglGetProcAddress);
|
|
738
|
+
return reinterpret_cast<Fn>(eglGetProcAddress(name));
|
|
739
|
+
#elif defined(_WIN32)
|
|
702
740
|
return reinterpret_cast<Fn>(GetProcAddress(static_cast<HMODULE>(library), name));
|
|
703
741
|
#else
|
|
704
742
|
return reinterpret_cast<Fn>(dlsym(library, name));
|
|
@@ -797,7 +835,7 @@ static void logEglFailure(const char *step) {
|
|
|
797
835
|
std::fprintf(stderr, "[three-angle-metal] %s failed, EGL error 0x%04x\n", step, lastEglError());
|
|
798
836
|
}
|
|
799
837
|
|
|
800
|
-
#if
|
|
838
|
+
#if defined(__APPLE__)
|
|
801
839
|
static CGFloat backingScaleForHostView(NSView *nativeView) {
|
|
802
840
|
CGFloat scale = nativeView.window ? nativeView.window.backingScaleFactor : 0.0;
|
|
803
841
|
if (scale <= 0.0 && nativeView.window.screen) scale = nativeView.window.screen.backingScaleFactor;
|
|
@@ -870,13 +908,13 @@ extern "C" void gea_three_webgl_update_size_uwp(double width, double height, dou
|
|
|
870
908
|
}
|
|
871
909
|
#endif
|
|
872
910
|
|
|
873
|
-
#if defined(
|
|
911
|
+
#if !defined(__APPLE__)
|
|
874
912
|
// The UWP frame driver owns its EGL context exclusively until it returns to
|
|
875
913
|
// CoreWindow event dispatch. Other hosts retain per-call binding semantics.
|
|
876
914
|
static thread_local bool gUwpFrameContextCurrent = false;
|
|
877
915
|
#endif
|
|
878
916
|
static bool makeCurrent(const char *label) {
|
|
879
|
-
#if defined(
|
|
917
|
+
#if !defined(__APPLE__)
|
|
880
918
|
if (gUwpFrameContextCurrent) return true;
|
|
881
919
|
#endif
|
|
882
920
|
if (!gWebGL.ready && gWebGL.context == EGL_NO_CONTEXT) return false;
|
|
@@ -907,7 +945,7 @@ static bool makeCurrent(const char *label) {
|
|
|
907
945
|
return true;
|
|
908
946
|
}
|
|
909
947
|
|
|
910
|
-
#if defined(
|
|
948
|
+
#if !defined(__APPLE__)
|
|
911
949
|
extern "C" bool gea_three_webgl_begin_frame_uwp() {
|
|
912
950
|
// Always rebind after the dispatcher, where arbitrary platform callbacks
|
|
913
951
|
// may have used a different context. No such callbacks run within the frame.
|
|
@@ -921,7 +959,7 @@ extern "C" void gea_three_webgl_end_frame_uwp() {
|
|
|
921
959
|
}
|
|
922
960
|
#endif
|
|
923
961
|
|
|
924
|
-
#if
|
|
962
|
+
#if defined(__APPLE__)
|
|
925
963
|
static bool rebuildWindowSurface(const char *label) {
|
|
926
964
|
if (!gWebGL.eglCreateWindowSurface || !gWebGL.eglDestroySurface || !gWebGL.eglMakeCurrent ||
|
|
927
965
|
!gWebGL.metalLayer || !gWebGL.config || gWebGL.context == EGL_NO_CONTEXT) {
|
|
@@ -1029,6 +1067,11 @@ static bool loadGlSymbols() {
|
|
|
1029
1067
|
LOAD_GL(glPixelStorei, PFNGLPIXELSTOREIPROC)
|
|
1030
1068
|
LOAD_GL(glPolygonOffset, PFNGLPOLYGONOFFSETPROC)
|
|
1031
1069
|
LOAD_GL(glReadPixels, PFNGLREADPIXELSPROC)
|
|
1070
|
+
LOAD_GL(glMapBufferRange, PFNGLMAPBUFFERRANGEPROC)
|
|
1071
|
+
LOAD_GL(glUnmapBuffer, PFNGLUNMAPBUFFERPROC)
|
|
1072
|
+
LOAD_GL(glFenceSync, PFNGLFENCESYNCPROC)
|
|
1073
|
+
LOAD_GL(glClientWaitSync, PFNGLCLIENTWAITSYNCPROC)
|
|
1074
|
+
LOAD_GL(glDeleteSync, PFNGLDELETESYNCPROC)
|
|
1032
1075
|
LOAD_GL(glCopyTexImage2D,PFNGLCOPYTEXIMAGE2DPROC)
|
|
1033
1076
|
LOAD_GL(glCopyTexSubImage2D,PFNGLCOPYTEXSUBIMAGE2DPROC)
|
|
1034
1077
|
LOAD_GL(glBlitFramebuffer, PFNGLBLITFRAMEBUFFERPROC)
|
|
@@ -1047,6 +1090,10 @@ static bool loadGlSymbols() {
|
|
|
1047
1090
|
LOAD_GL(glTexParameteri, PFNGLTEXPARAMETERIPROC)
|
|
1048
1091
|
LOAD_GL(glTexSubImage2D, PFNGLTEXSUBIMAGE2DPROC)
|
|
1049
1092
|
LOAD_GL(glTexStorage2D, PFNGLTEXSTORAGE2DPROC)
|
|
1093
|
+
gWebGL.glTexImage3D = loadGl<PFNGLTEXIMAGE3DPROC>("glTexImage3D");
|
|
1094
|
+
gWebGL.glTexSubImage3D = loadGl<PFNGLTEXSUBIMAGE3DPROC>("glTexSubImage3D");
|
|
1095
|
+
gWebGL.glTexStorage3D = loadGl<PFNGLTEXSTORAGE3DPROC>("glTexStorage3D");
|
|
1096
|
+
gWebGL.glFramebufferTextureLayer = loadGl<PFNGLFRAMEBUFFERTEXTURELAYERPROC>("glFramebufferTextureLayer");
|
|
1050
1097
|
LOAD_GL(glUniform1f, PFNGLUNIFORM1FPROC)
|
|
1051
1098
|
LOAD_GL(glUniform1fv, PFNGLUNIFORM1FVPROC)
|
|
1052
1099
|
LOAD_GL(glUniform1i, PFNGLUNIFORM1IPROC)
|
|
@@ -1082,7 +1129,7 @@ static bool loadGlSymbols() {
|
|
|
1082
1129
|
return true;
|
|
1083
1130
|
}
|
|
1084
1131
|
|
|
1085
|
-
#if defined(
|
|
1132
|
+
#if !defined(__APPLE__)
|
|
1086
1133
|
extern "C" bool gea_three_webgl_attach_uwp(
|
|
1087
1134
|
void *nativeWindow,
|
|
1088
1135
|
#else
|
|
@@ -1097,7 +1144,13 @@ extern "C" bool gea_three_webgl_attach(
|
|
|
1097
1144
|
smokeLog("[three-angle-metal] WebGL host attach requested");
|
|
1098
1145
|
if (gWebGL.ready) return true;
|
|
1099
1146
|
|
|
1100
|
-
#if defined(
|
|
1147
|
+
#if defined(GEA_WEBGL_STATIC_GLES)
|
|
1148
|
+
// Linked into the program: nothing to load; loadSymbol resolves through
|
|
1149
|
+
// eglGetProcAddress. The handles only need to be non-null.
|
|
1150
|
+
static int staticGles;
|
|
1151
|
+
gWebGL.egl = &staticGles;
|
|
1152
|
+
gWebGL.gles = &staticGles;
|
|
1153
|
+
#elif defined(_WIN32)
|
|
1101
1154
|
// An override (e.g. threejs-rendozer's GeaRendozerGLES.dll) first, then the
|
|
1102
1155
|
// packaged ANGLE of a UWP app, then a plain desktop load next to the exe.
|
|
1103
1156
|
auto openWin32 = [](const wchar_t *overrideEnv, const wchar_t *name) -> HMODULE {
|
|
@@ -1114,7 +1167,7 @@ extern "C" bool gea_three_webgl_attach(
|
|
|
1114
1167
|
};
|
|
1115
1168
|
gWebGL.egl = openWin32(L"GEA_ANGLE_EGL_DYLIB", L"libEGL.dll");
|
|
1116
1169
|
gWebGL.gles = openWin32(L"GEA_ANGLE_GLES_DYLIB", L"libGLESv2.dll");
|
|
1117
|
-
#
|
|
1170
|
+
#elif defined(__APPLE__)
|
|
1118
1171
|
static const char *const eglPaths[] = {
|
|
1119
1172
|
"/Applications/Visual Studio Code.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib",
|
|
1120
1173
|
"/Applications/Cursor.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib",
|
|
@@ -1132,6 +1185,8 @@ extern "C" bool gea_three_webgl_attach(
|
|
|
1132
1185
|
|
|
1133
1186
|
gWebGL.egl = openFirst("GEA_ANGLE_EGL_DYLIB", eglPaths);
|
|
1134
1187
|
gWebGL.gles = openFirst("GEA_ANGLE_GLES_DYLIB", glesPaths);
|
|
1188
|
+
#else
|
|
1189
|
+
#error "load libEGL/libGLESv2 for this platform, or build with GEA_WEBGL_STATIC_GLES"
|
|
1135
1190
|
#endif
|
|
1136
1191
|
if (!gWebGL.egl || !gWebGL.gles) {
|
|
1137
1192
|
smokeLog("[three-angle-metal] ANGLE libEGL/libGLESv2 were not found");
|
|
@@ -1209,7 +1264,7 @@ extern "C" bool gea_three_webgl_attach(
|
|
|
1209
1264
|
}
|
|
1210
1265
|
gWebGL.config = config;
|
|
1211
1266
|
|
|
1212
|
-
#if defined(
|
|
1267
|
+
#if !defined(__APPLE__)
|
|
1213
1268
|
gWebGL.nativeWindow = nativeWindow;
|
|
1214
1269
|
gea_three_webgl_update_size_uwp(width, height, devicePixelRatio);
|
|
1215
1270
|
if (gWebGL.eglCreateWindowSurface) {
|
|
@@ -1275,7 +1330,7 @@ extern "C" bool gea_three_webgl_attach(
|
|
|
1275
1330
|
|
|
1276
1331
|
gWebGL.ready = true;
|
|
1277
1332
|
gWebGL.glViewport(0, 0, gWebGL.widthPx, gWebGL.heightPx);
|
|
1278
|
-
#if
|
|
1333
|
+
#if defined(__APPLE__)
|
|
1279
1334
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1280
1335
|
if (gWebGL.ready && rebuildWindowSurface("eglCreateWindowSurface(deferred)")) {
|
|
1281
1336
|
smokeLog("[three-angle-metal] WebGL EGL surface rebound at %dx%d", gWebGL.widthPx, gWebGL.heightPx);
|
|
@@ -1391,7 +1446,7 @@ extern "C" void gea_three_webgl_swap() {
|
|
|
1391
1446
|
// TEMP-DIAG: GEA_THREE_VIEW_DUMP=1 — at frame 60, log the window's full
|
|
1392
1447
|
// subview tree and a hit-test grid so overlay views that would swallow
|
|
1393
1448
|
// mouse events are visible without Accessibility permission.
|
|
1394
|
-
#if
|
|
1449
|
+
#if defined(__APPLE__)
|
|
1395
1450
|
if (std::getenv("GEA_THREE_VIEW_DUMP")) {
|
|
1396
1451
|
static int viewDumpCount = 0;
|
|
1397
1452
|
if (++viewDumpCount == 60) {
|
|
@@ -1424,6 +1479,16 @@ extern "C" void gea_three_webgl_swap() {
|
|
|
1424
1479
|
}
|
|
1425
1480
|
}
|
|
1426
1481
|
#endif
|
|
1482
|
+
// The debug dump and recording read the window into client memory. A PIXEL_PACK_BUFFER the app left
|
|
1483
|
+
// bound (WebGL2 asynchronous readback) would make the pointer a buffer offset instead, so the read
|
|
1484
|
+
// runs with it unbound and the binding is restored afterwards.
|
|
1485
|
+
const auto readWindowRgba = [](int w, int h, unsigned char *rgba) {
|
|
1486
|
+
GLint packBuffer = 0;
|
|
1487
|
+
if (gWebGL.glGetIntegerv) gWebGL.glGetIntegerv(0x88ED /* PIXEL_PACK_BUFFER_BINDING */, &packBuffer);
|
|
1488
|
+
if (packBuffer) gWebGL.glBindBuffer(0x88EB /* PIXEL_PACK_BUFFER */, 0);
|
|
1489
|
+
gWebGL.glReadPixels(0, 0, w, h, GL_RGBA_VALUE, GL_UNSIGNED_BYTE, rgba);
|
|
1490
|
+
if (packBuffer) gWebGL.glBindBuffer(0x88EB, static_cast<GLuint>(packBuffer));
|
|
1491
|
+
};
|
|
1427
1492
|
// Debug frame dump: GEA_WEBGL_DUMP_FRAME=<path-prefix> writes the full
|
|
1428
1493
|
// framebuffer of frames 90/180/300 as PPM (P6) — visual ground truth for
|
|
1429
1494
|
// native-vs-browser comparisons without needing a window screenshot.
|
|
@@ -1434,7 +1499,7 @@ extern "C" void gea_three_webgl_swap() {
|
|
|
1434
1499
|
const int w = gWebGL.widthPx;
|
|
1435
1500
|
const int h = gWebGL.heightPx;
|
|
1436
1501
|
std::vector<unsigned char> rgba(static_cast<size_t>(w) * h * 4);
|
|
1437
|
-
|
|
1502
|
+
readWindowRgba(w, h, rgba.data());
|
|
1438
1503
|
char path[512];
|
|
1439
1504
|
std::snprintf(path, sizeof path, "%s-f%d.ppm", dumpPrefix, dumpCount);
|
|
1440
1505
|
if (FILE *file = std::fopen(path, "wb")) {
|
|
@@ -1483,7 +1548,7 @@ extern "C" void gea_three_webgl_swap() {
|
|
|
1483
1548
|
if (due > recordWritten && gWebGL.widthPx == recordW && gWebGL.heightPx == recordH) {
|
|
1484
1549
|
std::vector<unsigned char> rgba(static_cast<size_t>(recordW) * recordH * 4);
|
|
1485
1550
|
std::vector<unsigned char> rgb(static_cast<size_t>(recordW) * recordH * 3);
|
|
1486
|
-
|
|
1551
|
+
readWindowRgba(recordW, recordH, rgba.data());
|
|
1487
1552
|
for (int y = 0; y < recordH; ++y) {
|
|
1488
1553
|
const unsigned char *src = rgba.data() + static_cast<size_t>(recordH - 1 - y) * recordW * 4;
|
|
1489
1554
|
unsigned char *dst = rgb.data() + static_cast<size_t>(y) * recordW * 3;
|
|
@@ -2498,6 +2563,36 @@ extern "C" void gea_three_webgl_tex_image_2d_bytes(double target, double level,
|
|
|
2498
2563
|
gWebGL.glTexImage2D(asGLenum(target), asGLint(level), asGLint(internalFormat), asGLsizei(width), asGLsizei(height), 0, asGLenum(format), asGLenum(type), bytes);
|
|
2499
2564
|
}
|
|
2500
2565
|
|
|
2566
|
+
static bool requireGl(const void *fn, const char *name) {
|
|
2567
|
+
if (fn) return true;
|
|
2568
|
+
smokeLog("[native-webgl] %s is not provided by this GLES; the call is dropped", name);
|
|
2569
|
+
return false;
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
extern "C" void gea_three_webgl_tex_image_3d_bytes(double target, double level, double internalFormat, double width, double height, double depth, double format, double type, const void* bytes, double) {
|
|
2573
|
+
GEA_WEBGL_VOID("texImage3DBytes");
|
|
2574
|
+
if (!requireGl(reinterpret_cast<const void *>(gWebGL.glTexImage3D), "glTexImage3D")) return;
|
|
2575
|
+
gWebGL.glTexImage3D(asGLenum(target), asGLint(level), asGLint(internalFormat), asGLsizei(width), asGLsizei(height), asGLsizei(depth), 0, asGLenum(format), asGLenum(type), bytes);
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
extern "C" void gea_three_webgl_tex_sub_image_3d_bytes(double target, double level, double xoffset, double yoffset, double zoffset, double width, double height, double depth, double format, double type, const void* bytes, double) {
|
|
2579
|
+
GEA_WEBGL_VOID("texSubImage3DBytes");
|
|
2580
|
+
if (!requireGl(reinterpret_cast<const void *>(gWebGL.glTexSubImage3D), "glTexSubImage3D")) return;
|
|
2581
|
+
gWebGL.glTexSubImage3D(asGLenum(target), asGLint(level), asGLint(xoffset), asGLint(yoffset), asGLint(zoffset), asGLsizei(width), asGLsizei(height), asGLsizei(depth), asGLenum(format), asGLenum(type), bytes);
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
extern "C" void gea_three_webgl_tex_storage_3d(double target, double levels, double internalFormat, double width, double height, double depth) {
|
|
2585
|
+
GEA_WEBGL_VOID("texStorage3D");
|
|
2586
|
+
if (!requireGl(reinterpret_cast<const void *>(gWebGL.glTexStorage3D), "glTexStorage3D")) return;
|
|
2587
|
+
gWebGL.glTexStorage3D(asGLenum(target), asGLsizei(std::max(1.0, levels)), asGLenum(internalFormat), asGLsizei(width), asGLsizei(height), asGLsizei(depth));
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
extern "C" void gea_three_webgl_framebuffer_texture_layer(double target, double attachment, double texture, double level, double layer) {
|
|
2591
|
+
GEA_WEBGL_VOID("framebufferTextureLayer");
|
|
2592
|
+
if (!requireGl(reinterpret_cast<const void *>(gWebGL.glFramebufferTextureLayer), "glFramebufferTextureLayer")) return;
|
|
2593
|
+
gWebGL.glFramebufferTextureLayer(asGLenum(target), asGLenum(attachment), asGLuint(texture), asGLint(level), asGLint(layer));
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2501
2596
|
extern "C" void gea_three_webgl_tex_sub_image_2d_bytes(double target, double level, double xoffset, double yoffset, double width, double height, double format, double type, const void* bytes, double) {
|
|
2502
2597
|
GEA_WEBGL_VOID("texSubImage2DBytes");
|
|
2503
2598
|
gWebGL.glTexSubImage2D(asGLenum(target), asGLint(level), asGLint(xoffset), asGLint(yoffset), asGLsizei(width), asGLsizei(height), asGLenum(format), asGLenum(type), bytes);
|
|
@@ -2805,6 +2900,106 @@ extern "C" void gea_three_webgl_read_pixels_bytes(double x, double y, double wid
|
|
|
2805
2900
|
gWebGL.glReadPixels(asGLint(x),asGLint(y),asGLsizei(width),asGLsizei(height),asGLenum(format),asGLenum(type),bytes);
|
|
2806
2901
|
}
|
|
2807
2902
|
|
|
2903
|
+
// WebGL2 asynchronous readback (three's readRenderTargetPixelsAsync): readPixels into the bound
|
|
2904
|
+
// PIXEL_PACK_BUFFER at a byte offset, a fence, polling, then getBufferSubData through a read mapping.
|
|
2905
|
+
extern "C" void gea_three_webgl_read_pixels_pack(double x, double y, double width, double height, double format, double type, double offset) {
|
|
2906
|
+
GEA_WEBGL_VOID("readPixels");
|
|
2907
|
+
GLint packBuffer = 0;
|
|
2908
|
+
gWebGL.glGetIntegerv(0x88ED, &packBuffer);
|
|
2909
|
+
if (!packBuffer || !std::isfinite(offset) || offset < 0 || std::floor(offset) != offset) { if (!hostReadbackError) hostReadbackError = 0x0502; return; }
|
|
2910
|
+
gWebGL.glReadPixels(asGLint(x), asGLint(y), asGLsizei(width), asGLsizei(height), asGLenum(format), asGLenum(type),
|
|
2911
|
+
reinterpret_cast<void *>(static_cast<std::uintptr_t>(offset)));
|
|
2912
|
+
}
|
|
2913
|
+
static std::unordered_map<std::uint32_t, GLsync> gWebGLSyncs;
|
|
2914
|
+
static std::uint32_t gWebGLNextSync = 1;
|
|
2915
|
+
extern "C" double gea_three_webgl_fence_sync() {
|
|
2916
|
+
GEA_WEBGL_DOUBLE("fenceSync");
|
|
2917
|
+
GLsync sync = gWebGL.glFenceSync(0x9117 /* SYNC_GPU_COMMANDS_COMPLETE */, 0);
|
|
2918
|
+
if (!sync) return 0.0;
|
|
2919
|
+
const std::uint32_t id = gWebGLNextSync++;
|
|
2920
|
+
gWebGLSyncs[id] = sync;
|
|
2921
|
+
return static_cast<double>(id);
|
|
2922
|
+
}
|
|
2923
|
+
extern "C" double gea_three_webgl_client_wait_sync(double sync, double flags, double timeout) {
|
|
2924
|
+
GEA_WEBGL_DOUBLE("clientWaitSync");
|
|
2925
|
+
auto it = gWebGLSyncs.find(static_cast<std::uint32_t>(sync));
|
|
2926
|
+
if (it == gWebGLSyncs.end()) return 0x911D; // WAIT_FAILED
|
|
2927
|
+
return static_cast<double>(gWebGL.glClientWaitSync(it->second, static_cast<GLbitfield>(flags), static_cast<GLuint64>(std::max(0.0, timeout))));
|
|
2928
|
+
}
|
|
2929
|
+
extern "C" void gea_three_webgl_delete_sync(double sync) {
|
|
2930
|
+
GEA_WEBGL_VOID("deleteSync");
|
|
2931
|
+
auto it = gWebGLSyncs.find(static_cast<std::uint32_t>(sync));
|
|
2932
|
+
if (it == gWebGLSyncs.end()) return;
|
|
2933
|
+
gWebGL.glDeleteSync(it->second);
|
|
2934
|
+
gWebGLSyncs.erase(it);
|
|
2935
|
+
}
|
|
2936
|
+
// GPU timers for the app's frame profiler, on GL_EXT_disjoint_timer_query.
|
|
2937
|
+
struct HostGpuTimers {
|
|
2938
|
+
bool initialized = false, supported = false;
|
|
2939
|
+
void (*gen)(GLsizei, GLuint *) = nullptr;
|
|
2940
|
+
void (*remove)(GLsizei, const GLuint *) = nullptr;
|
|
2941
|
+
void (*begin)(GLenum, GLuint) = nullptr;
|
|
2942
|
+
void (*end)(GLenum) = nullptr;
|
|
2943
|
+
void (*available)(GLuint, GLenum, GLuint *) = nullptr;
|
|
2944
|
+
void (*result)(GLuint, GLenum, std::uint64_t *) = nullptr;
|
|
2945
|
+
bool open = false;
|
|
2946
|
+
bool ensure() {
|
|
2947
|
+
if (initialized) return supported;
|
|
2948
|
+
initialized = true;
|
|
2949
|
+
const auto extensions = reinterpret_cast<const char *>(gWebGL.glGetString(0x1F03));
|
|
2950
|
+
const std::string list = " " + std::string(extensions ? extensions : "") + " ";
|
|
2951
|
+
if (list.find(" GL_EXT_disjoint_timer_query ") == std::string::npos) return false;
|
|
2952
|
+
gen = loadGl<decltype(gen)>("glGenQueriesEXT");
|
|
2953
|
+
remove = loadGl<decltype(remove)>("glDeleteQueriesEXT");
|
|
2954
|
+
begin = loadGl<decltype(begin)>("glBeginQueryEXT");
|
|
2955
|
+
end = loadGl<decltype(end)>("glEndQueryEXT");
|
|
2956
|
+
available = loadGl<decltype(available)>("glGetQueryObjectuivEXT");
|
|
2957
|
+
result = loadGl<decltype(result)>("glGetQueryObjectui64vEXT");
|
|
2958
|
+
supported = gen && remove && begin && end && available && result;
|
|
2959
|
+
return supported;
|
|
2960
|
+
}
|
|
2961
|
+
};
|
|
2962
|
+
static HostGpuTimers gHostGpuTimers;
|
|
2963
|
+
extern "C" double gea_three_webgl_timer_begin() {
|
|
2964
|
+
GEA_WEBGL_DOUBLE("timerBegin");
|
|
2965
|
+
auto &t = gHostGpuTimers;
|
|
2966
|
+
if (!t.ensure() || t.open) return 0.0;
|
|
2967
|
+
GLuint query = 0;
|
|
2968
|
+
t.gen(1, &query);
|
|
2969
|
+
if (!query) return 0.0;
|
|
2970
|
+
t.begin(0x88BF /* TIME_ELAPSED_EXT */, query);
|
|
2971
|
+
t.open = true;
|
|
2972
|
+
return static_cast<double>(query);
|
|
2973
|
+
}
|
|
2974
|
+
extern "C" void gea_three_webgl_timer_end() {
|
|
2975
|
+
GEA_WEBGL_VOID("timerEnd");
|
|
2976
|
+
auto &t = gHostGpuTimers;
|
|
2977
|
+
if (!t.supported || !t.open) return;
|
|
2978
|
+
t.end(0x88BF);
|
|
2979
|
+
t.open = false;
|
|
2980
|
+
}
|
|
2981
|
+
extern "C" double gea_three_webgl_timer_result(double timer) {
|
|
2982
|
+
GEA_WEBGL_DOUBLE("timerResult");
|
|
2983
|
+
auto &t = gHostGpuTimers;
|
|
2984
|
+
const GLuint query = static_cast<GLuint>(timer);
|
|
2985
|
+
if (!t.supported || !query) return 0.0;
|
|
2986
|
+
GLuint ready = 0;
|
|
2987
|
+
t.available(query, 0x8867 /* QUERY_RESULT_AVAILABLE */, &ready);
|
|
2988
|
+
if (!ready) return -1.0;
|
|
2989
|
+
std::uint64_t ns = 0;
|
|
2990
|
+
t.result(query, 0x8866 /* QUERY_RESULT */, &ns);
|
|
2991
|
+
t.remove(1, &query);
|
|
2992
|
+
return static_cast<double>(ns);
|
|
2993
|
+
}
|
|
2994
|
+
extern "C" void gea_three_webgl_get_buffer_sub_data_bytes(double target, double srcOffset, void *bytes, double byteLength) {
|
|
2995
|
+
GEA_WEBGL_VOID("getBufferSubData");
|
|
2996
|
+
if (!bytes || !(byteLength > 0) || !(srcOffset >= 0)) { if (!hostReadbackError) hostReadbackError = 0x0501; return; }
|
|
2997
|
+
void *mapped = gWebGL.glMapBufferRange(asGLenum(target), static_cast<GLintptr>(srcOffset), static_cast<GLsizeiptr>(byteLength), 0x0001 /* MAP_READ_BIT */);
|
|
2998
|
+
if (!mapped) { if (!hostReadbackError) hostReadbackError = 0x0502; return; }
|
|
2999
|
+
std::memcpy(bytes, mapped, static_cast<std::size_t>(byteLength));
|
|
3000
|
+
gWebGL.glUnmapBuffer(asGLenum(target));
|
|
3001
|
+
}
|
|
3002
|
+
|
|
2808
3003
|
extern "C" void gea_three_webgl_blit_framebuffer(double sx0,double sy0,double sx1,double sy1,double dx0,double dy0,double dx1,double dy1,double mask,double filter) {
|
|
2809
3004
|
GEA_WEBGL_VOID("blitFramebuffer");
|
|
2810
3005
|
gWebGL.glBlitFramebuffer(asGLint(sx0),asGLint(sy0),asGLint(sx1),asGLint(sy1),asGLint(dx0),asGLint(dy0),asGLint(dx1),asGLint(dy1),asGLenum(mask),asGLenum(filter));
|
package/package.json
CHANGED
package/src/inflate.ts
CHANGED
|
@@ -18,7 +18,7 @@ const codeLengthOrder = new Uint8Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4,
|
|
|
18
18
|
// native build narrows a function's integer locals to machine integers, but a
|
|
19
19
|
// class's number fields stay doubles, and on a core without a double FPU (the
|
|
20
20
|
// ESP32-S31) every bit read through a field was several soft-float calls --
|
|
21
|
-
// inflating
|
|
21
|
+
// inflating a game's asset kit at boot took over 80 seconds.
|
|
22
22
|
|
|
23
23
|
/** Decoder state: read position, bit buffer, bits held, bytes written. */
|
|
24
24
|
const position = 0
|
package/src/nativeWebGL.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
1
2
|
declare function threeWebGLCopyTexImage2D(target:number,level:number,internalFormat:number,x:number,y:number,width:number,height:number,border:number):void;
|
|
3
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
2
4
|
declare function threeWebGLCopyTexSubImage2D(target:number,level:number,xoffset:number,yoffset:number,x:number,y:number,width:number,height:number):void;
|
|
3
5
|
/// <reference path="./gea-native-types.d.ts" />
|
|
4
6
|
|
|
@@ -93,6 +95,7 @@ type NativeHandleKind =
|
|
|
93
95
|
| 'program'
|
|
94
96
|
| 'renderbuffer'
|
|
95
97
|
| 'shader'
|
|
98
|
+
| 'sync'
|
|
96
99
|
| 'texture'
|
|
97
100
|
| 'uniform'
|
|
98
101
|
| 'vertexArray'
|
|
@@ -200,11 +203,26 @@ function typedArrayKind(value: BufferSourceLike): number {
|
|
|
200
203
|
return 1
|
|
201
204
|
}
|
|
202
205
|
|
|
206
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
203
207
|
declare function threeWebGLBlitFramebuffer(sx0:number, sy0:number, sx1:number, sy1:number, dx0:number, dy0:number, dx1:number, dy1:number, mask:number, filter:number): void
|
|
208
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
204
209
|
declare function threeWebGLRenderbufferStorageMultisample(target:number, samples:number, format:number, width:number, height:number): void
|
|
205
210
|
type ReadPixelsDestination = Uint8Array | Uint16Array | Float32Array | Uint32Array | Int32Array | Int16Array | Int8Array
|
|
206
211
|
// Mutates the destination view; deliberately not marked host-inert.
|
|
212
|
+
/** @gea-host-typed-array-element-writes Stores pixels into the destination typed array's elements only; no other property of any object, no callbacks. */
|
|
207
213
|
declare function threeWebGLReadPixels(x: number, y: number, width: number, height: number, format: number, type: number, destination: ReadPixelsDestination, offset: number): void
|
|
214
|
+
// WebGL2 asynchronous readback: into the bound PIXEL_PACK_BUFFER, fenced, then read through getBufferSubData.
|
|
215
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
216
|
+
declare function threeWebGLReadPixelsPack(x: number, y: number, width: number, height: number, format: number, type: number, offset: number): void
|
|
217
|
+
/** @gea-host-inert Creates a GL sync object; never calls back into script. */
|
|
218
|
+
declare function threeWebGLFenceSync(): number
|
|
219
|
+
/** @gea-host-inert Reads scalar arguments, waits on GL state only; never calls back into script. */
|
|
220
|
+
declare function threeWebGLClientWaitSync(sync: number, flags: number, timeout: number): number
|
|
221
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
222
|
+
declare function threeWebGLDeleteSync(sync: number): void
|
|
223
|
+
// Mutates the destination view; deliberately not marked host-inert.
|
|
224
|
+
/** @gea-host-typed-array-element-writes Stores buffer bytes into the destination typed array's elements only; no other property of any object, no callbacks. */
|
|
225
|
+
declare function threeWebGLGetBufferSubData(target: number, srcByteOffset: number, destination: ReadPixelsDestination, dstOffset: number, length: number): void
|
|
208
226
|
|
|
209
227
|
function zeroF32Array(length: number): f32[] {
|
|
210
228
|
const out: f32[] = []
|
|
@@ -254,6 +272,14 @@ declare function threeWebGLTexImage2D(target: number, level: number, internalFor
|
|
|
254
272
|
declare function threeWebGLTexSubImage2D(target: number, level: number, xoffset: number, yoffset: number, width: number, height: number, format: number, type: number, values: BufferSourceLike): void
|
|
255
273
|
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
256
274
|
declare function threeWebGLTexStorage2D(target: number, levels: number, internalFormat: number, width: number, height: number): void
|
|
275
|
+
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
276
|
+
declare function threeWebGLTexImage3D(target: number, level: number, internalFormat: number, width: number, height: number, depth: number, format: number, type: number, values: BufferSourceLike): void
|
|
277
|
+
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
278
|
+
declare function threeWebGLTexSubImage3D(target: number, level: number, xoffset: number, yoffset: number, zoffset: number, width: number, height: number, depth: number, format: number, type: number, values: BufferSourceLike): void
|
|
279
|
+
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
280
|
+
declare function threeWebGLTexStorage3D(target: number, levels: number, internalFormat: number, width: number, height: number, depth: number): void
|
|
281
|
+
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
282
|
+
declare function threeWebGLFramebufferTextureLayer(target: number, attachment: number, texture: number, level: number, layer: number): void
|
|
257
283
|
|
|
258
284
|
// Shader source keyed by the stable native GL handle. A NativeShader instance
|
|
259
285
|
// can be value-copied when it round-trips through a function-return / gcv
|
|
@@ -663,6 +689,10 @@ export class NativeWebGL2RenderingContext {
|
|
|
663
689
|
readonly TIMEOUT_EXPIRED = 0x911B
|
|
664
690
|
readonly CONDITION_SATISFIED = 0x911C
|
|
665
691
|
readonly WAIT_FAILED = 0x911D
|
|
692
|
+
readonly SYNC_GPU_COMMANDS_COMPLETE = 0x9117
|
|
693
|
+
readonly PIXEL_PACK_BUFFER = 0x88EB
|
|
694
|
+
readonly PIXEL_PACK_BUFFER_BINDING = 0x88ED
|
|
695
|
+
readonly STREAM_READ = 0x88E1
|
|
666
696
|
readonly COLOR = 0x1800
|
|
667
697
|
readonly DEPTH_COMPONENT = 0x1902
|
|
668
698
|
readonly ALPHA = 0x1906
|
|
@@ -935,11 +965,14 @@ export class NativeWebGL2RenderingContext {
|
|
|
935
965
|
if (name === this.MAX_RENDERBUFFER_SIZE || name === this.MAX_3D_TEXTURE_SIZE) return 16384
|
|
936
966
|
if (name === this.MAX_ARRAY_TEXTURE_LAYERS) return 2048
|
|
937
967
|
if (name === this.MAX_VERTEX_ATTRIBS) return 16
|
|
938
|
-
|
|
968
|
+
// threejs-rendozer binds up to 32 textures per program (both stages); three checks a program's total against this.
|
|
969
|
+
if (name === this.MAX_TEXTURE_IMAGE_UNITS || name === this.MAX_VERTEX_TEXTURE_IMAGE_UNITS) return 32
|
|
939
970
|
if (name === this.MAX_COMBINED_TEXTURE_IMAGE_UNITS) return 32
|
|
940
971
|
if (name === this.MAX_VERTEX_UNIFORM_VECTORS || name === this.MAX_FRAGMENT_UNIFORM_VECTORS) return 1024
|
|
941
972
|
if (name === this.MAX_VARYING_VECTORS) return 32
|
|
942
|
-
|
|
973
|
+
// threejs-rendozer reports 8 when every multisampled renderbuffer format supports it (and steps down per format).
|
|
974
|
+
if (name === this.MAX_SAMPLES) return 8
|
|
975
|
+
if (name === this.SAMPLES) return 4
|
|
943
976
|
if (name === this.MAX_UNIFORM_BUFFER_BINDINGS) return 24
|
|
944
977
|
if (name === this.DEPTH_BITS) return 24
|
|
945
978
|
if (name === this.STENCIL_BITS) return 8
|
|
@@ -1106,10 +1139,10 @@ export class NativeWebGL2RenderingContext {
|
|
|
1106
1139
|
texImage2D(target: number, level: number, internalFormat: number, widthOrFormat: number, heightOrType: number, borderOrSource?: number | NativeTextureImage | null, format?: number, type?: number, pixels?: BufferSourceLike | null): void {
|
|
1107
1140
|
if (typeof borderOrSource === 'number' && typeof format === 'number' && typeof type === 'number') {
|
|
1108
1141
|
threeWebGLTexImage2D(target, level, internalFormat, widthOrFormat, heightOrType, format, type, pixels ?? new Uint8Array(0))
|
|
1109
|
-
} else if (borderOrSource && typeof borderOrSource !== 'number') {
|
|
1142
|
+
} else if (borderOrSource !== null && borderOrSource !== undefined && typeof borderOrSource !== 'number') {
|
|
1110
1143
|
threeWebGLTexImage2D(target, level, internalFormat, borderOrSource.width, borderOrSource.height, widthOrFormat, heightOrType, borderOrSource.data)
|
|
1111
1144
|
} else {
|
|
1112
|
-
throw new Error(
|
|
1145
|
+
throw new Error(`Native texImage2D requires dimensions and typed pixels, or a decoded NativeTextureImage (target ${target}, level ${level}, internal format ${internalFormat}, source ${borderOrSource === null ? 'null' : typeof borderOrSource})`)
|
|
1113
1146
|
}
|
|
1114
1147
|
}
|
|
1115
1148
|
texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, width: number, height: number, format: number, type: number, pixels: BufferSourceLike): void {
|
|
@@ -1125,9 +1158,15 @@ export class NativeWebGL2RenderingContext {
|
|
|
1125
1158
|
// Three uploads 3D and array textures only from typed `image.data` /
|
|
1126
1159
|
// `mipmap.data` (or `null` to allocate), the same carrier the 2D uploads
|
|
1127
1160
|
// take; no TexImageSource ever reaches these entry points.
|
|
1128
|
-
texImage3D(
|
|
1129
|
-
|
|
1130
|
-
|
|
1161
|
+
texImage3D(target: number, level: number, internalFormat: number, width: number, height: number, depth: number, _border: number, format: number, type: number, source: BufferSourceLike | null): void {
|
|
1162
|
+
threeWebGLTexImage3D(target, level, internalFormat, width, height, depth, format, type, source ?? new Uint8Array(0))
|
|
1163
|
+
}
|
|
1164
|
+
texSubImage3D(target: number, level: number, xoffset: number, yoffset: number, zoffset: number, width: number, height: number, depth: number, format: number, type: number, source: BufferSourceLike): void {
|
|
1165
|
+
threeWebGLTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, source)
|
|
1166
|
+
}
|
|
1167
|
+
texStorage3D(target: number, levels: number, internalFormat: number, width: number, height: number, depth: number): void {
|
|
1168
|
+
threeWebGLTexStorage3D(target, levels, internalFormat, width, height, depth)
|
|
1169
|
+
}
|
|
1131
1170
|
|
|
1132
1171
|
createVertexArray(): NativeHandle { return createHandle('vertexArray', nativeWebGLCreateVertexArray()) }
|
|
1133
1172
|
bindVertexArray(vertexArray: NativeHandle | null): void { nativeWebGLBindVertexArray(nullableNativeHandle(vertexArray)) }
|
|
@@ -1150,7 +1189,9 @@ export class NativeWebGL2RenderingContext {
|
|
|
1150
1189
|
framebufferRenderbuffer(target: number, attachment: number, renderbuffertarget: number, renderbuffer: NativeHandle | null): void {
|
|
1151
1190
|
nativeWebGLFramebufferRenderbuffer(target, attachment, renderbuffertarget, nullableNativeHandle(renderbuffer))
|
|
1152
1191
|
}
|
|
1153
|
-
framebufferTextureLayer(
|
|
1192
|
+
framebufferTextureLayer(target: number, attachment: number, texture: NativeHandle | null, level: number, layer: number): void {
|
|
1193
|
+
threeWebGLFramebufferTextureLayer(target, attachment, nullableNativeHandle(texture), level, layer)
|
|
1194
|
+
}
|
|
1154
1195
|
drawBuffers(buffers: number[]): void { nativeWebGLDrawBuffers(buffers[0] ?? this.COLOR_ATTACHMENT0) }
|
|
1155
1196
|
|
|
1156
1197
|
clearColor(r: number, g: number, b: number, a: number): void { nativeWebGLClearColor(r, g, b, a) }
|
|
@@ -1193,7 +1234,13 @@ export class NativeWebGL2RenderingContext {
|
|
|
1193
1234
|
invalidateFramebuffer(_target: number, _attachments: BufferSourceLike): void {}
|
|
1194
1235
|
blitFramebuffer(sx0:number, sy0:number, sx1:number, sy1:number, dx0:number, dy0:number, dx1:number, dy1:number, mask:number, filter:number): void { threeWebGLBlitFramebuffer(sx0,sy0,sx1,sy1,dx0,dy0,dx1,dy1,mask,filter) }
|
|
1195
1236
|
readBuffer(_src: number): void {}
|
|
1196
|
-
|
|
1237
|
+
// WebGL2 also reads into the bound PIXEL_PACK_BUFFER at a byte offset (three's
|
|
1238
|
+
// readRenderTargetPixelsAsync): the GPU copy is recorded without waiting for the GPU.
|
|
1239
|
+
readPixels(x: number, y: number, width: number, height: number, format: number, type: number, destination: ReadPixelsDestination | number, offset = 0): void {
|
|
1240
|
+
if (typeof destination === 'number') {
|
|
1241
|
+
threeWebGLReadPixelsPack(x, y, width, height, format, type, destination)
|
|
1242
|
+
return
|
|
1243
|
+
}
|
|
1197
1244
|
threeWebGLReadPixels(x, y, width, height, format, type, destination, offset)
|
|
1198
1245
|
}
|
|
1199
1246
|
copyTexImage2D(target: number, level: number, internalFormat: number, x: number, y: number, width: number, height: number, border: number): void {threeWebGLCopyTexImage2D(target,level,internalFormat,x,y,width,height,border);}
|
|
@@ -1202,7 +1249,9 @@ export class NativeWebGL2RenderingContext {
|
|
|
1202
1249
|
clearBufferiv(_buffer: number, _drawbuffer: number, _values: BufferSourceLike): void {}
|
|
1203
1250
|
clearBufferuiv(_buffer: number, _drawbuffer: number, _values: BufferSourceLike): void {}
|
|
1204
1251
|
getBufferParameter(_target: number, _pname: number): number { return 0 }
|
|
1205
|
-
getBufferSubData(
|
|
1252
|
+
getBufferSubData(target: number, srcByteOffset: number, destination: ReadPixelsDestination, dstOffset = 0, length = 0): void {
|
|
1253
|
+
threeWebGLGetBufferSubData(target, srcByteOffset, destination, dstOffset, length)
|
|
1254
|
+
}
|
|
1206
1255
|
getFramebufferAttachmentParameter(_target: number, _attachment: number, _pname: number): number { return 0 }
|
|
1207
1256
|
getRenderbufferParameter(_target: number, _pname: number): number { return 0 }
|
|
1208
1257
|
getTexParameter(_target: number, _pname: number): number { return 0 }
|
|
@@ -1213,9 +1262,14 @@ export class NativeWebGL2RenderingContext {
|
|
|
1213
1262
|
uniformBlockBinding(_program: NativeProgram | null, _uniformBlockIndex: number, _uniformBlockBinding: number): void {}
|
|
1214
1263
|
bindBufferBase(_target: number, _index: number, _buffer: NativeHandle | null): void {}
|
|
1215
1264
|
bindBufferRange(_target: number, _index: number, _buffer: NativeHandle | null, _offset: number, _size: number): void {}
|
|
1216
|
-
fenceSync(_condition: number, _flags: number):
|
|
1217
|
-
|
|
1218
|
-
|
|
1265
|
+
fenceSync(_condition: number, _flags: number): NativeHandle | null {
|
|
1266
|
+
const sync = threeWebGLFenceSync()
|
|
1267
|
+
return sync ? createHandle('sync', sync) : null
|
|
1268
|
+
}
|
|
1269
|
+
clientWaitSync(sync: NativeHandle | null, flags: number, timeout: number): number {
|
|
1270
|
+
return sync ? threeWebGLClientWaitSync(nativeHandle(sync), flags, timeout) : this.WAIT_FAILED
|
|
1271
|
+
}
|
|
1272
|
+
deleteSync(sync: NativeHandle | null): void { if (sync) threeWebGLDeleteSync(nativeHandle(sync)) }
|
|
1219
1273
|
isBuffer(_buffer: NativeHandle | null): boolean { return true }
|
|
1220
1274
|
isFramebuffer(_framebuffer: NativeHandle | null): boolean { return true }
|
|
1221
1275
|
isProgram(_program: NativeProgram | null): boolean { return true }
|