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 CHANGED
@@ -25,7 +25,9 @@ npm run build
25
25
  npm test
26
26
  ```
27
27
 
28
- [🧊Demo](https://webgl2/was.hm)
28
+ [🧊Demo WebGL/WASHM](https://webgl2.was.hm)
29
+
30
+ ![🧊Demo WebGL/WASHM -rotating cube around 35-40FPS](./webgl2-demo2.gif)
29
31
 
30
32
  ## ✨ Key Features
31
33
 
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 {Object} opts - options (unused for now)
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(opts = {}) {
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)), 'webgl2.wasm');
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('./webgl2.wasm', import.meta.url));
113
+ const resp = await fetch(new URL('./' + wasmFile, import.meta.url));
101
114
  if (!resp.ok) {
102
- throw new Error(`Failed to fetch webgl2.wasm: ${resp.status}`);
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.22",
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/was.hm"
25
+ "homepage": "https://webgl2.was.hm"
22
26
  ,
23
27
  "files": [
24
28
  "index.js",
@@ -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) { this._assertNotDestroyed(); throw new Error('not implemented'); }
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() { this._assertNotDestroyed(); throw new Error('not implemented'); }
761
- bindVertexArray(vao) { this._assertNotDestroyed(); throw new Error('not implemented'); }
762
- deleteVertexArray(vao) { this._assertNotDestroyed(); throw new Error('not implemented'); }
763
- isVertexArray(vao) { this._assertNotDestroyed(); throw new Error('not implemented'); }
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) { this._assertNotDestroyed(); throw new Error('not implemented'); }
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