webgl2 1.2.1 → 1.2.4

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/coverage.md CHANGED
@@ -4,52 +4,43 @@
4
4
 
5
5
  | File | Lines Covered | Lines Missed | Total Lines | Coverage |
6
6
  |---|---|---|---|---:|
7
- | src/decompiler/ast.rs | 0 | 1 | 1 | 0.00% 🟡 |
8
- | src/decompiler/emitter.rs | 17 | 8 | 25 | 68.00% 🟡 |
9
- | src/decompiler/lifter.rs | 17 | 21 | 38 | 44.74% 🟠 |
10
- | src/decompiler/mod.rs | 8 | 6 | 14 | 57.14% 🟡 |
11
- | src/decompiler/module.rs | 3 | 1 | 4 | 75.00% 🟡 |
12
- | src/decompiler/parser.rs | 15 | 2 | 17 | 88.24% 🟢 |
13
- | src/decompiler/simplifier.rs | 54 | 19 | 73 | 73.97% 🟡 |
14
- | src/error.rs | 8 | 15 | 23 | 34.78% 🟠 |
15
- | src/lib.rs | 314 | 224 | 538 | 58.36% 🟡 |
16
- | src/naga_wasm_backend/backend.rs | 62 | 2 | 64 | 96.88% 🟢 |
17
- | src/naga_wasm_backend/call_lowering.rs | 19 | 0 | 19 | 100.00% 🟢 |
18
- | src/naga_wasm_backend/control_flow.rs | 30 | 40 | 70 | 42.86% 🟠 |
19
- | src/naga_wasm_backend/debug/stub.rs | 20 | 0 | 20 | 100.00% 🟢 |
20
- | src/naga_wasm_backend/expressions.rs | 65 | 109 | 174 | 37.36% 🟠 |
21
- | src/naga_wasm_backend/function_abi.rs | 25 | 0 | 25 | 100.00% 🟢 |
22
- | src/naga_wasm_backend/functions/prep.rs | 4 | 0 | 4 | 100.00% 🟢 |
23
- | src/naga_wasm_backend/functions/registry.rs | 4 | 0 | 4 | 100.00% 🟢 |
24
- | src/naga_wasm_backend/memory_layout.rs | 9 | 0 | 9 | 100.00% 🟢 |
25
- | src/naga_wasm_backend/mod.rs | 1 | 0 | 1 | 100.00% 🟢 |
26
- | src/naga_wasm_backend/output_layout.rs | 4 | 2 | 6 | 66.67% 🟡 |
27
- | src/naga_wasm_backend/types.rs | 11 | 0 | 11 | 100.00% 🟢 |
28
- | src/wasm_gl_emu/device.rs | 20 | 4 | 24 | 83.33% 🟢 |
7
+ | src/coverage.rs | 18 | 1 | 19 | 94.74% 🟢 |
8
+ | src/decompiler/ast.rs | 4 | 0 | 4 | 100.00% 🟢 |
9
+ | src/decompiler/emitter.rs | 35 | 2 | 37 | 94.59% 🟢 |
10
+ | src/decompiler/lifter.rs | 11 | 14 | 25 | 44.00% 🟠 |
11
+ | src/decompiler/simplifier.rs | 30 | 1 | 31 | 96.77% 🟢 |
12
+ | src/error.rs | 13 | 2 | 15 | 86.67% 🟢 |
13
+ | src/lib.rs | 87 | 299 | 386 | 22.54% 🟠 |
14
+ | src/naga_wasm_backend/backend.rs | 173 | 24 | 197 | 87.82% 🟢 |
15
+ | src/naga_wasm_backend/call_lowering.rs | 22 | 3 | 25 | 88.00% 🟢 |
16
+ | src/naga_wasm_backend/control_flow.rs | 37 | 41 | 78 | 47.44% 🟠 |
17
+ | src/naga_wasm_backend/debug/stub.rs | 25 | 9 | 34 | 73.53% 🟡 |
18
+ | src/naga_wasm_backend/expressions.rs | 143 | 155 | 298 | 47.99% 🟠 |
19
+ | src/naga_wasm_backend/function_abi.rs | 31 | 0 | 31 | 100.00% 🟢 |
20
+ | src/naga_wasm_backend/functions/prep.rs | 4 | 2 | 6 | 66.67% 🟡 |
21
+ | src/naga_wasm_backend/functions/registry.rs | 0 | 1 | 1 | 0.00% 🟡 |
22
+ | src/naga_wasm_backend/memory_layout.rs | 16 | 4 | 20 | 80.00% 🟢 |
23
+ | src/naga_wasm_backend/mod.rs | 5 | 5 | 10 | 50.00% 🟡 |
24
+ | src/naga_wasm_backend/output_layout.rs | 2 | 1 | 3 | 66.67% 🟡 |
25
+ | src/wasm_gl_emu/device.rs | 49 | 12 | 61 | 80.33% 🟢 |
29
26
  | src/wasm_gl_emu/framebuffer.rs | 3 | 1 | 4 | 75.00% 🟡 |
30
- | src/wasm_gl_emu/rasterizer.rs | 32 | 18 | 50 | 64.00% 🟡 |
31
- | src/wasm_gl_emu/transfer.rs | 19 | 7 | 26 | 73.08% 🟡 |
32
- | src/webgl2_context/blend.rs | 0 | 3 | 3 | 0.00% 🟡 |
33
- | src/webgl2_context/buffers.rs | 20 | 4 | 24 | 83.33% 🟢 |
34
- | src/webgl2_context/drawing.rs | 13 | 0 | 13 | 100.00% 🟢 |
35
- | src/webgl2_context/framebuffers.rs | 11 | 1 | 12 | 91.67% 🟢 |
36
- | src/webgl2_context/registry.rs | 7 | 0 | 7 | 100.00% 🟢 |
37
- | src/webgl2_context/renderbuffers.rs | 10 | 0 | 10 | 100.00% 🟢 |
38
- | src/webgl2_context/shaders.rs | 112 | 14 | 126 | 88.89% 🟢 |
39
- | src/webgl2_context/state.rs | 16 | 4 | 20 | 80.00% 🟢 |
40
- | src/webgl2_context/textures.rs | 25 | 9 | 34 | 73.53% 🟡 |
41
- | src/webgl2_context/types.rs | 16 | 0 | 16 | 100.00% 🟢 |
42
- | src/webgl2_context/vaos.rs | 35 | 0 | 35 | 100.00% 🟢 |
43
- | src/webgpu/adapter.rs | 2 | 0 | 2 | 100.00% 🟢 |
44
- | src/webgpu/backend.rs | 70 | 26 | 96 | 72.92% 🟡 |
45
- | src/webgpu/command.rs | 3 | 1 | 4 | 75.00% 🟡 |
46
- | **Total** | **1104** | **542** | **1646** | **67.07% 🟡** |
27
+ | src/wasm_gl_emu/rasterizer.rs | 52 | 58 | 110 | 47.27% 🟠 |
28
+ | src/wasm_gl_emu/transfer.rs | 11 | 16 | 27 | 40.74% 🟠 |
29
+ | src/webgl2_context/shaders.rs | 160 | 14 | 174 | 91.95% 🟢 |
30
+ | src/webgl2_context/state.rs | 80 | 1 | 81 | 98.77% 🟢 |
31
+ | src/webgl2_context/textures.rs | 22 | 7 | 29 | 75.86% 🟡 |
32
+ | src/webgl2_context/types.rs | 52 | 14 | 66 | 78.79% 🟡 |
33
+ | src/webgl2_context/vaos.rs | 25 | 19 | 44 | 56.82% 🟡 |
34
+ | src/webgpu/adapter.rs | 3 | 2 | 5 | 60.00% 🟡 |
35
+ | src/webgpu/backend.rs | 68 | 20 | 88 | 77.27% 🟡 |
36
+ | src/webgpu/command.rs | 1 | 1 | 2 | 50.00% 🟡 |
37
+ | **Total** | **1182** | **729** | **1911** | **61.85% 🟡** |
47
38
 
48
39
  ## Top Missed Files
49
40
 
50
41
  | File | Lines Missed | Illustrative Line | Coverage |
51
42
  |---|---|---|---:|
52
- | src/lib.rs | 224/538 | [1033] `/// Use a program.` | 58.36% 🟡 |
53
- | src/naga_wasm_backend/expressions.rs | 109/174 | [1504] `for j in 0..count {` | 37.36% 🟠 |
54
- | src/naga_wasm_backend/control_flow.rs | 40/70 | [218] `for (s, s_span) in body.span_iter() {` | 42.86% 🟠 |
55
- | src/webgpu/backend.rs | 26/96 | [1404] `}` | 72.92% 🟡 |
43
+ | src/lib.rs | 299/386 | [1994] `) -> u32 {` | 22.54% 🟠 |
44
+ | src/naga_wasm_backend/expressions.rs | 155/298 | [1845] `translate_expression(*argument, ctx)?;` | 47.99% 🟠 |
45
+ | src/wasm_gl_emu/rasterizer.rs | 58/110 | [370] `match eq {` | 47.27% 🟠 |
46
+ | src/naga_wasm_backend/control_flow.rs | 41/78 | [535] `let types = super::types::naga_to_wasm_types(` | 47.44% 🟠 |
package/demo.js CHANGED
@@ -19,7 +19,8 @@ const animationState = {
19
19
  // Global rendering context (lazy initialized)
20
20
  let renderContext = null;
21
21
 
22
- async function initializeRenderContext() {
22
+ /** @param {{ useBilinear?: boolean }} [options] */
23
+ async function initializeRenderContext({ useBilinear } = {}) {
23
24
  if (renderContext) return renderContext;
24
25
 
25
26
  let loadLocal =
@@ -35,6 +36,7 @@ async function initializeRenderContext() {
35
36
 
36
37
  const gl = await webGL2({ debug: true });
37
38
  gl.viewport(0, 0, 640, 480);
39
+ gl.enable(gl.DEPTH_TEST);
38
40
 
39
41
  // Shaders
40
42
  const vsSource = /* glsl */`#version 300 es
@@ -164,6 +166,10 @@ async function initializeRenderContext() {
164
166
  }
165
167
  }
166
168
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, texData);
169
+ if (!useBilinear) {
170
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
171
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
172
+ }
167
173
 
168
174
  const uTextureLoc = gl.getUniformLocation(program, "u_texture");
169
175
  gl.uniform1i(uTextureLoc, 0);
@@ -254,8 +260,10 @@ async function initializeRenderContext() {
254
260
  return renderContext;
255
261
  }
256
262
 
257
- async function renderCube(elapsedTime = 0) {
258
- const ctx = await initializeRenderContext();
263
+ async function renderCube({ elapsedTime, useBilinear } = {}) {
264
+ if (!elapsedTime) elapsedTime = 0;
265
+
266
+ const ctx = await initializeRenderContext({ useBilinear });
259
267
  const { gl, program, mvpLoc, perspective, translate, rotateX, rotateY, multiply } = ctx;
260
268
 
261
269
  // Calculate rotation angle: 1 full rotation (2π) in 5 seconds
@@ -549,7 +557,7 @@ async function animate() {
549
557
  if (!animationState.running) return;
550
558
 
551
559
  const elapsedTime = Date.now() - animationState.startTime;
552
- const result = await renderCube(elapsedTime);
560
+ const result = await renderCube({ elapsedTime });
553
561
  const { pixels, width, height } = result;
554
562
 
555
563
  await displayFrame(pixels, width, height);
@@ -599,7 +607,7 @@ async function runTerminalAnimation(width, height, duration = 20000) {
599
607
  const avgFps = elapsedTime > 0 ? Math.round((frameCount * 1000) / elapsedTime) : 0;
600
608
 
601
609
  // Render cube with current rotation
602
- const result = await renderCube(elapsedTime);
610
+ const result = await renderCube({ elapsedTime, useBilinear: true });
603
611
  const { pixels } = result;
604
612
 
605
613
  // Generate ASCII art
package/index.js CHANGED
@@ -10,14 +10,14 @@ import {
10
10
  getShaderGlsl,
11
11
  decompileWasmToGlsl
12
12
  } from './src/webgl2_context.js';
13
- import { GPU, GPUBufferUsage, GPUMapMode, GPUTextureUsage } from './src/webgpu_context.js';
13
+ import { GPU, GPUBufferUsage, GPUMapMode, GPUTextureUsage, GPUShaderStage } from './src/webgpu_context.js';
14
14
 
15
15
  export const debug = {
16
16
  getLcovReport,
17
17
  resetLcovReport
18
18
  };
19
19
 
20
- export { ERR_OK, ERR_INVALID_HANDLE, GPUBufferUsage, GPUMapMode, GPUTextureUsage, getShaderModule, getShaderWat, getShaderGlsl, decompileWasmToGlsl };
20
+ export { ERR_OK, ERR_INVALID_HANDLE, GPUBufferUsage, GPUMapMode, GPUTextureUsage, GPUShaderStage, getShaderModule, getShaderWat, getShaderGlsl, decompileWasmToGlsl };
21
21
 
22
22
  /**
23
23
  * Simple allocator for function table indices.
@@ -25,9 +25,10 @@ export { ERR_OK, ERR_INVALID_HANDLE, GPUBufferUsage, GPUMapMode, GPUTextureUsage
25
25
  */
26
26
  class TableAllocator {
27
27
  constructor() {
28
- // Rust uses the first ~1900 slots for its indirect function table (dyn calls, etc).
29
- // We must valid collision by starting allocations after that region.
30
- this.nextIndex = 2000;
28
+ // Rust uses many slots for its indirect function table (dyn calls, etc).
29
+ // We must avoid collision by starting allocations after that region.
30
+ // Increased from 2000 to 5000 for safety in larger modules.
31
+ this.nextIndex = 5000;
31
32
  this.freeList = [];
32
33
  }
33
34
 
@@ -99,7 +100,7 @@ export async function webGL2({ debug = (typeof process !== 'undefined' ? process
99
100
  }
100
101
  });
101
102
  }
102
- const { ex, instance, sharedTable, tableAllocator } = await promise;
103
+ const { ex, instance, sharedTable, tableAllocator, turboGlobals } = await promise;
103
104
 
104
105
  // Initialize coverage if available
105
106
  if (ex.wasm_init_coverage && ex.COV_MAP_PTR) {
@@ -136,7 +137,8 @@ export async function webGL2({ debug = (typeof process !== 'undefined' ? process
136
137
  height,
137
138
  debugShaders: !!debugShaders,
138
139
  sharedTable,
139
- tableAllocator
140
+ tableAllocator,
141
+ turboGlobals
140
142
  });
141
143
 
142
144
  if (size && typeof size.width === 'number' && typeof size.height === 'number') {
@@ -167,15 +169,22 @@ export async function webGPU({ debug = (typeof process !== 'undefined' ? process
167
169
  }
168
170
  });
169
171
  }
170
- const { ex, instance } = await promise;
172
+
173
+ // Resolve the WASM initialization and return a WebGPU wrapper (GPU).
174
+ // Tests expect an object with `requestAdapter()`; return a `GPU` instance
175
+ // backed by the WASM exports and memory.
176
+ const { ex } = await promise;
171
177
  return new GPU(ex, ex.memory);
172
178
  }
173
179
 
174
180
  /**
175
- * @type {Map<boolean, Promise<{ ex: WebAssembly.Exports, instance: WebAssembly.Instance, module: WebAssembly.Module }>>}
181
+ * @type {Map<boolean, ReturnType<typeof initWASM>>}
176
182
  */
177
183
  const wasmCache = new Map();
178
184
 
185
+ /**
186
+ * @param {{ debug?: boolean }} [options]
187
+ */
179
188
  async function initWASM({ debug } = {}) {
180
189
  const wasmFile = debug ? 'webgl2.debug.wasm' : 'webgl2.wasm';
181
190
  let wasmBuffer;
@@ -202,39 +211,47 @@ async function initWASM({ debug } = {}) {
202
211
  // Compile WASM module
203
212
  const wasmModule = await WebAssembly.compile(wasmBuffer);
204
213
 
205
- // Instantiate WASM (no imports needed, memory is exported)
214
+ /**
215
+ * Instantiate WASM (no imports needed, memory is exported)
216
+ * @type {WebAssembly.Instance}
217
+ */
206
218
  let instance;
207
219
 
208
220
  // Create shared function table for direct shader calls
209
221
  const sharedTable = new WebAssembly.Table({
210
- initial: 4096, // Increased from 4096 to handle larger modules
211
- maximum: 8192, // Prevent unbounded growth
222
+ initial: 8192,
223
+ maximum: 65536,
212
224
  element: "anyfunc"
213
225
  });
214
226
  const tableAllocator = new TableAllocator();
215
227
 
228
+ // Create shared mutable globals that will be used by both the main module and
229
+ // transient shader modules. These are WebAssembly.Global objects with mutable
230
+ // i32 value so shaders can update pointer state directly.
231
+ const turboGlobals = {
232
+ ACTIVE_ATTR_PTR: new WebAssembly.Global({ value: 'i32', mutable: true }, 0),
233
+ ACTIVE_UNIFORM_PTR: new WebAssembly.Global({ value: 'i32', mutable: true }, 0),
234
+ ACTIVE_VARYING_PTR: new WebAssembly.Global({ value: 'i32', mutable: true }, 0),
235
+ ACTIVE_PRIVATE_PTR: new WebAssembly.Global({ value: 'i32', mutable: true }, 0),
236
+ ACTIVE_TEXTURE_PTR: new WebAssembly.Global({ value: 'i32', mutable: true }, 0),
237
+ ACTIVE_FRAME_SP: new WebAssembly.Global({ value: 'i32', mutable: true }, 0),
238
+ };
239
+
216
240
  const importObject = {
217
241
  env: {
218
242
  __indirect_function_table: sharedTable, // Exact name LLVM expects
243
+ memory: new WebAssembly.Memory({ initial: 100 }),
244
+ ACTIVE_ATTR_PTR: turboGlobals.ACTIVE_ATTR_PTR,
245
+ ACTIVE_UNIFORM_PTR: turboGlobals.ACTIVE_UNIFORM_PTR,
246
+ ACTIVE_VARYING_PTR: turboGlobals.ACTIVE_VARYING_PTR,
247
+ ACTIVE_PRIVATE_PTR: turboGlobals.ACTIVE_PRIVATE_PTR,
248
+ ACTIVE_TEXTURE_PTR: turboGlobals.ACTIVE_TEXTURE_PTR,
249
+ ACTIVE_FRAME_SP: turboGlobals.ACTIVE_FRAME_SP,
219
250
  print: (ptr, len) => {
220
251
  const mem = new Uint8Array(instance.exports.memory.buffer);
221
252
  const bytes = mem.subarray(ptr, ptr + len);
222
253
  console.log(new TextDecoder('utf-8').decode(bytes));
223
254
  },
224
- wasm_execute_shader: (ctx, type, tableIdx, attrPtr, uniformPtr, varyingPtr, privatePtr, texturePtr) => {
225
- const gl = WasmWebGL2RenderingContext._contexts.get(ctx);
226
- if (gl) {
227
- gl._executeShader(type, tableIdx, attrPtr, uniformPtr, varyingPtr, privatePtr, texturePtr);
228
- } else {
229
- // General device execution (WebGPU)
230
- if (tableIdx > 0 && sharedTable) {
231
- const func = sharedTable.get(tableIdx);
232
- if (func) {
233
- func(ctx, type, tableIdx, attrPtr, uniformPtr, varyingPtr, privatePtr, texturePtr);
234
- }
235
- }
236
- }
237
- },
238
255
  wasm_register_shader: (ptr, len) => {
239
256
  const mem = new Uint8Array(instance.exports.memory.buffer);
240
257
  const bytes = mem.slice(ptr, ptr + len);
@@ -244,6 +261,12 @@ async function initWASM({ debug } = {}) {
244
261
  const env = {
245
262
  memory: instance.exports.memory,
246
263
  __indirect_function_table: sharedTable,
264
+ ACTIVE_ATTR_PTR: turboGlobals.ACTIVE_ATTR_PTR,
265
+ ACTIVE_UNIFORM_PTR: turboGlobals.ACTIVE_UNIFORM_PTR,
266
+ ACTIVE_VARYING_PTR: turboGlobals.ACTIVE_VARYING_PTR,
267
+ ACTIVE_PRIVATE_PTR: turboGlobals.ACTIVE_PRIVATE_PTR,
268
+ ACTIVE_TEXTURE_PTR: turboGlobals.ACTIVE_TEXTURE_PTR,
269
+ ACTIVE_FRAME_SP: turboGlobals.ACTIVE_FRAME_SP,
247
270
  };
248
271
 
249
272
  // Copy math functions
@@ -265,6 +288,22 @@ async function initWASM({ debug } = {}) {
265
288
  }
266
289
  return index;
267
290
  },
291
+ wasm_release_shader_index: (idx) => {
292
+ tableAllocator.free(idx);
293
+ },
294
+ wasm_sync_turbo_globals: (attr, uniform, varying, private_, texture, frame_sp) => {
295
+ try {
296
+ turboGlobals.ACTIVE_ATTR_PTR.value = attr >>> 0;
297
+ turboGlobals.ACTIVE_UNIFORM_PTR.value = uniform >>> 0;
298
+ turboGlobals.ACTIVE_VARYING_PTR.value = varying >>> 0;
299
+ turboGlobals.ACTIVE_PRIVATE_PTR.value = private_ >>> 0;
300
+ turboGlobals.ACTIVE_TEXTURE_PTR.value = texture >>> 0;
301
+ turboGlobals.ACTIVE_FRAME_SP.value = frame_sp >>> 0;
302
+ } catch (e) {
303
+ // Defensive: if the globals are immutable or not set, at least avoid crashing
304
+ console.warn('wasm_sync_turbo_globals failed to set globals', e);
305
+ }
306
+ },
268
307
  dispatch_uncaptured_error: (ptr, len) => {
269
308
  const mem = new Uint8Array(instance.exports.memory.buffer);
270
309
  const bytes = mem.subarray(ptr, ptr + len);
@@ -305,7 +344,7 @@ async function initWASM({ debug } = {}) {
305
344
  if (!(ex.memory instanceof WebAssembly.Memory)) {
306
345
  throw new Error('WASM module missing memory export');
307
346
  }
308
- return { ex, instance, module: wasmModule, sharedTable, tableAllocator };
347
+ return { ex, instance, module: wasmModule, sharedTable, tableAllocator, turboGlobals };
309
348
  }
310
349
 
311
350
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webgl2",
3
- "version": "1.2.1",
3
+ "version": "1.2.4",
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",
@@ -11,7 +11,6 @@
11
11
  "build-debug-distill": "cargo run --bin distill_wasm --features cli -- webgl2.debug.wasm --output webgl2.debug.wasm",
12
12
  "build-debug": "npm run build-debug-wasm-only && npm run build-debug-distill",
13
13
  "build": "npm run build-release && npm run build-debug",
14
- "prepublishOnly": "npm run build",
15
14
  "test": "node --import ./test/all-coverage.js --test test/**/*.test.js test/*.test.js"
16
15
  },
17
16
  "repository": {
@@ -30,5 +29,8 @@
30
29
  "webgl2.debug.wasm",
31
30
  "*.md",
32
31
  "LICENSE"
33
- ]
32
+ ],
33
+ "dependencies": {
34
+ "pngjs": "^7.0.0"
35
+ }
34
36
  }