webgl2 1.0.22 → 1.1.0
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/README.md +3 -1
- package/index.js +21 -8
- package/package.json +7 -3
- package/src/webgl2_context.js +114 -6
- package/webgl2.wasm +0 -0
package/README.md
CHANGED
package/index.js
CHANGED
|
@@ -40,11 +40,13 @@ const isNode =
|
|
|
40
40
|
* 3. Creates a Rust-owned context via wasm_create_context()
|
|
41
41
|
* 4. Returns a WasmWebGL2RenderingContext JS wrapper
|
|
42
42
|
*
|
|
43
|
-
* @param {
|
|
43
|
+
* @param {{
|
|
44
|
+
* debug?: boolean,
|
|
45
|
+
* }} [opts] - options
|
|
44
46
|
* @returns {Promise<WasmWebGL2RenderingContext>}
|
|
45
47
|
* @throws {Error} if WASM loading or instantiation fails
|
|
46
48
|
*/
|
|
47
|
-
async function webGL2(
|
|
49
|
+
async function webGL2({ debug } = {}) {
|
|
48
50
|
// Load WASM binary
|
|
49
51
|
const { ex, instance } = await (
|
|
50
52
|
wasmInitPromise ||
|
|
@@ -52,7 +54,7 @@ async function webGL2(opts = {}) {
|
|
|
52
54
|
// ensure success is cached but not failure
|
|
53
55
|
let succeeded = false;
|
|
54
56
|
try {
|
|
55
|
-
const wasm = await initWASM();
|
|
57
|
+
const wasm = await initWASM({ debug });
|
|
56
58
|
succeeded = true;
|
|
57
59
|
return wasm;
|
|
58
60
|
} finally {
|
|
@@ -61,6 +63,16 @@ async function webGL2(opts = {}) {
|
|
|
61
63
|
}
|
|
62
64
|
})());
|
|
63
65
|
|
|
66
|
+
// Initialize coverage if available
|
|
67
|
+
if (ex.wasm_init_coverage && ex.COV_MAP_PTR) {
|
|
68
|
+
const mapPtr = ex.COV_MAP_PTR.value;
|
|
69
|
+
// Read num_entries from the start of the map data
|
|
70
|
+
// mapPtr is aligned to 16 bytes, so we can use Uint32Array
|
|
71
|
+
const mem = new Uint32Array(ex.memory.buffer);
|
|
72
|
+
const numEntries = mem[mapPtr >>> 2];
|
|
73
|
+
ex.wasm_init_coverage(numEntries);
|
|
74
|
+
}
|
|
75
|
+
|
|
64
76
|
// Create a context in WASM
|
|
65
77
|
const ctxHandle = ex.wasm_create_context();
|
|
66
78
|
if (ctxHandle === 0) {
|
|
@@ -82,14 +94,15 @@ async function webGL2(opts = {}) {
|
|
|
82
94
|
*/
|
|
83
95
|
var wasmInitPromise;
|
|
84
96
|
|
|
85
|
-
async function initWASM() {
|
|
97
|
+
async function initWASM({ debug } = {}) {
|
|
98
|
+
const wasmFile = debug ? 'webgl2.debug.wasm' : 'webgl2.wasm';
|
|
86
99
|
let wasmBuffer;
|
|
87
100
|
if (isNode) {
|
|
88
101
|
// Use dynamic imports so this module can be loaded in the browser too.
|
|
89
102
|
const path = await import('path');
|
|
90
103
|
const fs = await import('fs');
|
|
91
104
|
const { fileURLToPath } = await import('url');
|
|
92
|
-
const wasmPath = path.join(path.dirname(fileURLToPath(import.meta.url)),
|
|
105
|
+
const wasmPath = path.join(path.dirname(fileURLToPath(import.meta.url)), wasmFile);
|
|
93
106
|
if (!fs.existsSync(wasmPath)) {
|
|
94
107
|
throw new Error(`WASM not found at ${wasmPath}. Run: npm run build:wasm`);
|
|
95
108
|
}
|
|
@@ -97,9 +110,9 @@ async function initWASM() {
|
|
|
97
110
|
wasmBuffer = fs.readFileSync(wasmPath);
|
|
98
111
|
} else {
|
|
99
112
|
// Browser: fetch the wasm relative to this module
|
|
100
|
-
const resp = await fetch(new URL('./
|
|
113
|
+
const resp = await fetch(new URL('./' + wasmFile, import.meta.url));
|
|
101
114
|
if (!resp.ok) {
|
|
102
|
-
throw new Error(`Failed to fetch
|
|
115
|
+
throw new Error(`Failed to fetch ${wasmFile}: ${resp.status}`);
|
|
103
116
|
}
|
|
104
117
|
wasmBuffer = await resp.arrayBuffer();
|
|
105
118
|
}
|
|
@@ -133,7 +146,7 @@ async function initWASM() {
|
|
|
133
146
|
if (!(ex.memory instanceof WebAssembly.Memory)) {
|
|
134
147
|
throw new Error('WASM module missing memory export');
|
|
135
148
|
}
|
|
136
|
-
return wasmInitPromise = { ex, instance };
|
|
149
|
+
return wasmInitPromise = { ex, instance, module: wasmModule };
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
/**
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webgl2",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "WebGL2 tools to derisk large GPU projects on the web beyond toys and demos.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "node ./index.js",
|
|
9
|
-
"build": "cargo build --target wasm32-unknown-unknown --release && node -e \"fs.copyFileSync('target/wasm32-unknown-unknown/release/webgl2.wasm', 'webgl2.wasm')\"",
|
|
9
|
+
"build-release": "cargo build --target wasm32-unknown-unknown --release && node -e \"fs.copyFileSync('target/wasm32-unknown-unknown/release/webgl2.wasm', 'webgl2.wasm')\"",
|
|
10
|
+
"build-debug-wasm-only": "cargo build --target wasm32-unknown-unknown --features coverage --profile coverage && node -e \"fs.copyFileSync('target/wasm32-unknown-unknown/coverage/webgl2.wasm', 'webgl2.debug.wasm')\"",
|
|
11
|
+
"build-debug-distill": "cargo run --bin distill_wasm --features cli -- webgl2.debug.wasm --output webgl2.debug.wasm",
|
|
12
|
+
"build-debug": "npm run build-debug-wasm-only && npm run build-debug-distill",
|
|
13
|
+
"build": "npm run build-release && npm run build-debug",
|
|
10
14
|
"prepublishOnly": "npm run build",
|
|
11
15
|
"test": "node --test test/*.test.js",
|
|
12
16
|
"test:smoke": "npm run build && node ./test/smoke.js"
|
|
@@ -18,7 +22,7 @@
|
|
|
18
22
|
"keywords": [],
|
|
19
23
|
"author": "",
|
|
20
24
|
"license": "MIT",
|
|
21
|
-
"homepage": "https://webgl2
|
|
25
|
+
"homepage": "https://webgl2.was.hm"
|
|
22
26
|
,
|
|
23
27
|
"files": [
|
|
24
28
|
"index.js",
|
package/src/webgl2_context.js
CHANGED
|
@@ -44,6 +44,21 @@ export class WasmWebGL2RenderingContext {
|
|
|
44
44
|
BUFFER_SIZE = 0x8764;
|
|
45
45
|
NO_ERROR = 0;
|
|
46
46
|
|
|
47
|
+
TEXTURE_2D = 0x0DE1;
|
|
48
|
+
TEXTURE_WRAP_S = 0x2802;
|
|
49
|
+
TEXTURE_WRAP_T = 0x2803;
|
|
50
|
+
TEXTURE_MAG_FILTER = 0x2800;
|
|
51
|
+
TEXTURE_MIN_FILTER = 0x2801;
|
|
52
|
+
NEAREST = 0x2600;
|
|
53
|
+
LINEAR = 0x2601;
|
|
54
|
+
NEAREST_MIPMAP_NEAREST = 0x2700;
|
|
55
|
+
LINEAR_MIPMAP_NEAREST = 0x2701;
|
|
56
|
+
NEAREST_MIPMAP_LINEAR = 0x2702;
|
|
57
|
+
LINEAR_MIPMAP_LINEAR = 0x2703;
|
|
58
|
+
REPEAT = 0x2901;
|
|
59
|
+
CLAMP_TO_EDGE = 0x812F;
|
|
60
|
+
MIRRORED_REPEAT = 0x8370;
|
|
61
|
+
|
|
47
62
|
/**
|
|
48
63
|
* @param {WebAssembly.Instance} instance
|
|
49
64
|
* @param {u32} ctxHandle
|
|
@@ -716,7 +731,32 @@ export class WasmWebGL2RenderingContext {
|
|
|
716
731
|
}
|
|
717
732
|
}
|
|
718
733
|
|
|
719
|
-
bufferSubData(target, offset, data) {
|
|
734
|
+
bufferSubData(target, offset, data) {
|
|
735
|
+
this._assertNotDestroyed();
|
|
736
|
+
const ex = this._instance.exports;
|
|
737
|
+
if (!ex || typeof ex.wasm_ctx_buffer_sub_data !== 'function') {
|
|
738
|
+
throw new Error('wasm_ctx_buffer_sub_data not found');
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
let bytes;
|
|
742
|
+
if (data instanceof Uint8Array) bytes = data;
|
|
743
|
+
else if (ArrayBuffer.isView(data)) bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
744
|
+
else if (data instanceof ArrayBuffer) bytes = new Uint8Array(data);
|
|
745
|
+
else bytes = new Uint8Array(data); // Fallback for arrays
|
|
746
|
+
|
|
747
|
+
const len = bytes.length;
|
|
748
|
+
const ptr = ex.wasm_alloc(len);
|
|
749
|
+
if (ptr === 0) throw new Error('Failed to allocate memory for bufferSubData');
|
|
750
|
+
|
|
751
|
+
try {
|
|
752
|
+
const mem = new Uint8Array(ex.memory.buffer);
|
|
753
|
+
mem.set(bytes, ptr);
|
|
754
|
+
const code = ex.wasm_ctx_buffer_sub_data(this._ctxHandle, target >>> 0, offset >>> 0, ptr, len);
|
|
755
|
+
_checkErr(code, this._instance);
|
|
756
|
+
} finally {
|
|
757
|
+
ex.wasm_free(ptr);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
720
760
|
copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) { this._assertNotDestroyed(); throw new Error('not implemented'); }
|
|
721
761
|
getBufferParameter(target, pname) {
|
|
722
762
|
this._assertNotDestroyed();
|
|
@@ -757,10 +797,52 @@ export class WasmWebGL2RenderingContext {
|
|
|
757
797
|
drawRangeElements(mode, start, end, count, type, offset) { this._assertNotDestroyed(); throw new Error('not implemented'); }
|
|
758
798
|
drawBuffers(buffers) { this._assertNotDestroyed(); throw new Error('not implemented'); }
|
|
759
799
|
|
|
760
|
-
createVertexArray() {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
800
|
+
createVertexArray() {
|
|
801
|
+
this._assertNotDestroyed();
|
|
802
|
+
const ex = this._instance.exports;
|
|
803
|
+
if (!ex || typeof ex.wasm_ctx_create_vertex_array !== 'function') {
|
|
804
|
+
throw new Error('wasm_ctx_create_vertex_array not found');
|
|
805
|
+
}
|
|
806
|
+
const handle = ex.wasm_ctx_create_vertex_array(this._ctxHandle);
|
|
807
|
+
if (handle === 0) return null;
|
|
808
|
+
return { _handle: handle, _type: 'WebGLVertexArrayObject' };
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
bindVertexArray(vao) {
|
|
812
|
+
this._assertNotDestroyed();
|
|
813
|
+
const ex = this._instance.exports;
|
|
814
|
+
if (!ex || typeof ex.wasm_ctx_bind_vertex_array !== 'function') {
|
|
815
|
+
throw new Error('wasm_ctx_bind_vertex_array not found');
|
|
816
|
+
}
|
|
817
|
+
const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao ? (vao >>> 0) : 0);
|
|
818
|
+
const code = ex.wasm_ctx_bind_vertex_array(this._ctxHandle, handle);
|
|
819
|
+
_checkErr(code, this._instance);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
deleteVertexArray(vao) {
|
|
823
|
+
this._assertNotDestroyed();
|
|
824
|
+
const ex = this._instance.exports;
|
|
825
|
+
if (!ex || typeof ex.wasm_ctx_delete_vertex_array !== 'function') {
|
|
826
|
+
throw new Error('wasm_ctx_delete_vertex_array not found');
|
|
827
|
+
}
|
|
828
|
+
const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao >>> 0);
|
|
829
|
+
const code = ex.wasm_ctx_delete_vertex_array(this._ctxHandle, handle);
|
|
830
|
+
_checkErr(code, this._instance);
|
|
831
|
+
if (vao && typeof vao === 'object') {
|
|
832
|
+
try { vao._handle = 0; vao._deleted = true; } catch (e) { /* ignore */ }
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
isVertexArray(vao) {
|
|
837
|
+
this._assertNotDestroyed();
|
|
838
|
+
const ex = this._instance.exports;
|
|
839
|
+
if (!ex || typeof ex.wasm_ctx_is_vertex_array !== 'function') {
|
|
840
|
+
throw new Error('wasm_ctx_is_vertex_array not found');
|
|
841
|
+
}
|
|
842
|
+
const handle = vao && typeof vao === 'object' && typeof vao._handle === 'number' ? vao._handle : (vao >>> 0);
|
|
843
|
+
const res = ex.wasm_ctx_is_vertex_array(this._ctxHandle, handle);
|
|
844
|
+
return res !== 0;
|
|
845
|
+
}
|
|
764
846
|
|
|
765
847
|
createTransformFeedback() { this._assertNotDestroyed(); throw new Error('not implemented'); }
|
|
766
848
|
bindTransformFeedback(target, tf) { this._assertNotDestroyed(); throw new Error('not implemented'); }
|
|
@@ -798,7 +880,15 @@ export class WasmWebGL2RenderingContext {
|
|
|
798
880
|
const code = ex.wasm_ctx_active_texture(this._ctxHandle, texture >>> 0);
|
|
799
881
|
_checkErr(code, this._instance);
|
|
800
882
|
}
|
|
801
|
-
texParameteri(target, pname, param) {
|
|
883
|
+
texParameteri(target, pname, param) {
|
|
884
|
+
this._assertNotDestroyed();
|
|
885
|
+
const ex = this._instance.exports;
|
|
886
|
+
if (!ex || typeof ex.wasm_ctx_tex_parameter_i !== 'function') {
|
|
887
|
+
throw new Error('wasm_ctx_tex_parameter_i not found');
|
|
888
|
+
}
|
|
889
|
+
const code = ex.wasm_ctx_tex_parameter_i(this._ctxHandle, target >>> 0, pname >>> 0, param | 0);
|
|
890
|
+
_checkErr(code, this._instance);
|
|
891
|
+
}
|
|
802
892
|
generateMipmap(target) { this._assertNotDestroyed(); throw new Error('not implemented'); }
|
|
803
893
|
copyTexImage2D(target, level, internalformat, x, y, width, height, border) { this._assertNotDestroyed(); throw new Error('not implemented'); }
|
|
804
894
|
copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) { this._assertNotDestroyed(); throw new Error('not implemented'); }
|
|
@@ -1067,6 +1157,24 @@ export class WasmWebGL2RenderingContext {
|
|
|
1067
1157
|
}
|
|
1068
1158
|
this._verbosity = level;
|
|
1069
1159
|
}
|
|
1160
|
+
|
|
1161
|
+
/**
|
|
1162
|
+
* Get LCOV coverage report.
|
|
1163
|
+
* @returns {string}
|
|
1164
|
+
*/
|
|
1165
|
+
getLcovReport() {
|
|
1166
|
+
this._assertNotDestroyed();
|
|
1167
|
+
const ex = this._instance.exports;
|
|
1168
|
+
if (ex && typeof ex.wasm_get_lcov_report_ptr === 'function' && typeof ex.wasm_get_lcov_report_len === 'function') {
|
|
1169
|
+
const ptr = ex.wasm_get_lcov_report_ptr();
|
|
1170
|
+
const len = ex.wasm_get_lcov_report_len();
|
|
1171
|
+
if (ptr === 0 || len === 0) return '';
|
|
1172
|
+
const mem = new Uint8Array(ex.memory.buffer);
|
|
1173
|
+
const bytes = mem.subarray(ptr, ptr + len);
|
|
1174
|
+
return new TextDecoder('utf-8').decode(bytes);
|
|
1175
|
+
}
|
|
1176
|
+
return '';
|
|
1177
|
+
}
|
|
1070
1178
|
}
|
|
1071
1179
|
|
|
1072
1180
|
/**
|
package/webgl2.wasm
CHANGED
|
Binary file
|