webgl2 1.0.1 → 1.0.3
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 +120 -0
- package/docs/1-webgl-emulator.md +51 -0
- package/package.json +11 -3
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
## GLSL++: Unified WASM Core for Debugging and Generation
|
|
2
|
+
|
|
3
|
+
This plan is a comprehensive roadmap for the **GLSL++** project. The core is a single **WASM artifact** that provides two distinct, clean interfaces for both runtime emulation (Component 1) and build-time code generation (Component 2).
|
|
4
|
+
|
|
5
|
+
The entire system is focused on **Correctness and Debugging Fidelity**, leveraging existing Rust graphics crates to minimize the implementation of the $\sim$300 WebGL2 APIs.
|
|
6
|
+
|
|
7
|
+
-----
|
|
8
|
+
|
|
9
|
+
## I. Unified WASM Architecture and Delivery
|
|
10
|
+
|
|
11
|
+
The project compiles into a single `.wasm` file and a single `.js` glue file, ensuring maximum portability between Node.js and browsers.
|
|
12
|
+
|
|
13
|
+
### A. Final Artifacts
|
|
14
|
+
|
|
15
|
+
| Artifact | Content | Purpose |
|
|
16
|
+
| :--- | :--- | :--- |
|
|
17
|
+
| **`glsl_plus_plus.wasm`** | Compiled Rust code for both Component 1 (GL Emulation) and Component 2 (Transpiler). | The **Core Engine**. |
|
|
18
|
+
| **`glsl_plus_plus.js`** | Universal ES Module wrapper for asynchronous loading and initialization. | The **Clean Interface** for consumers. |
|
|
19
|
+
|
|
20
|
+
### B. Core Dependencies (Shared `Cargo.toml`)
|
|
21
|
+
|
|
22
|
+
| Crate | Role | Component(s) |
|
|
23
|
+
| :--- | :--- | :--- |
|
|
24
|
+
| **`glow`** | **API Surface Definition (300+ methods).** | **C1** |
|
|
25
|
+
| **`wasm-bindgen`** | **JS/WASM Interop and Struct Export.** | **C1 & C2** |
|
|
26
|
+
| **`naga`** | **GLSL Parsing, Reflection, and IR Generation.** | **C1 & C2** |
|
|
27
|
+
| **`glam`** | **Vector/Matrix Math for Rasterizer.** | **C1** |
|
|
28
|
+
| **`hashbrown`** | **Fast Resource Registry (`u32` handles).** | **C1** |
|
|
29
|
+
| **`serde` / `serde-wasm-bindgen`** | **Safe, clean transfer of configuration and metadata objects.** | **C2** |
|
|
30
|
+
| **`wgpu-types`** | **Validated Resource Structs (optional, highly recommended).** | **C1** |
|
|
31
|
+
|
|
32
|
+
-----
|
|
33
|
+
|
|
34
|
+
## II. Component 1: WASM GL Emulation Core (Runtime) 🎨
|
|
35
|
+
|
|
36
|
+
This component implements the $\sim$300 WebGL2 API methods via the `glow` trait, running a pure software rasterizer for unit testing.
|
|
37
|
+
|
|
38
|
+
### A. External Interface: The Factory Function
|
|
39
|
+
|
|
40
|
+
Component 1 is accessed through a factory function to manage state initialization, ensuring the clean API shape requested.
|
|
41
|
+
|
|
42
|
+
```rust
|
|
43
|
+
// In src/gl_emulation.rs
|
|
44
|
+
#[wasm_bindgen(js_name = createGLContext)]
|
|
45
|
+
pub fn create_gl_context(width: u32, height: u32) -> GLContextHandle {
|
|
46
|
+
// Initializes internal state (framebuffer, viewport, etc.)
|
|
47
|
+
// Returns a handle to the initialized context instance.
|
|
48
|
+
// ...
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// All 300+ methods (e.g., buffer_data, draw_arrays) are implemented as methods on GLContextHandle
|
|
52
|
+
// and are automatically exposed by wasm-bindgen.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### B. Internal Implementation: The `glow::Context` Trait
|
|
56
|
+
|
|
57
|
+
| Implementation Area | Detail | Rationale |
|
|
58
|
+
| :--- | :--- | :--- |
|
|
59
|
+
| **API Surface** | Implement the **`glow::Context`** trait on the internal `WasmGLContext` struct. Methods not required for unit testing (e.g., `end_query`, `fence_sync`) are stubbed out to return success/no-op. | Minimizes implementation effort while guaranteeing API correctness. |
|
|
60
|
+
| **Resource Management** | **`WasmGLContext`** contains a **`hashbrown::HashMap<u32, ResourceData>`** registry. All API calls (`createBuffer`, `bindTexture`) reference and mutate resources based on these internal `u32` handles. | Avoids complex host pointers and ensures a deterministic, debuggable state machine. |
|
|
61
|
+
| **Buffer Data Transfer** | The body of `buffer_data()` performs a **transactional copy** of the incoming JavaScript `TypedArray` data directly into the target `Vec<u8>` within the WASM linear memory heap. | Ensures data is persistent and safely managed within the WASM sandbox. |
|
|
62
|
+
|
|
63
|
+
### C. The Software Rasterizer Loop (Triggered by `draw_arrays`)
|
|
64
|
+
|
|
65
|
+
The core of the emulation resides here:
|
|
66
|
+
|
|
67
|
+
1. **Shader Integration (Naga):** The `link_program` step uses **`naga`** to translate the GLSL into a Rust function pointer/closure (the **CPU Kernel**).
|
|
68
|
+
2. **Execution Stages:** The `draw_arrays()` body runs the full pipeline: Input Assembly $\rightarrow$ **Vertex Kernel Execution** (calling the Rust function for each vertex) $\rightarrow$ Rasterization (`glam` math) $\rightarrow$ **Fragment Kernel Execution** (calling the Rust function for each pixel).
|
|
69
|
+
3. **Output:** Writes the final color values to the **`WasmGLContext.framebuffer`** array.
|
|
70
|
+
|
|
71
|
+
### D. Final Output
|
|
72
|
+
|
|
73
|
+
The last step exposes the pixel data cleanly for display:
|
|
74
|
+
|
|
75
|
+
```rust
|
|
76
|
+
// In src/gl_emulation.rs
|
|
77
|
+
#[wasm_bindgen(js_name = presentFrame)]
|
|
78
|
+
pub fn present_frame(handle: &GLContextHandle) -> js_sys::Uint8Array {
|
|
79
|
+
// Safely creates a view/copy of the framebuffer Vec<u8> for JavaScript.
|
|
80
|
+
// ...
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
-----
|
|
85
|
+
|
|
86
|
+
## III. Component 2: Transpiler/Codegen Tool (Build-Time) 🛠️
|
|
87
|
+
|
|
88
|
+
Component 2 runs once during the build process, taking GLSL source and returning a structured object containing the generated JS code and metadata. It operates as a stateless function.
|
|
89
|
+
|
|
90
|
+
### A. External Interface: Structured Object Return
|
|
91
|
+
|
|
92
|
+
The function accepts the GLSL source and a native JS options object, returning a structured JS object that prevents string-whackery.
|
|
93
|
+
|
|
94
|
+
```rust
|
|
95
|
+
// In src/codegen.rs
|
|
96
|
+
#[wasm_bindgen(js_name = generateKernelJS)]
|
|
97
|
+
pub fn generate_kernel_js(
|
|
98
|
+
glsl_source: &str,
|
|
99
|
+
options_js: JsValue // Incoming JS object for configuration
|
|
100
|
+
) -> Result<GeneratedOutput, JsValue> {
|
|
101
|
+
// ... logic ...
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### B. Internal Implementation: Reflection and Codec
|
|
106
|
+
|
|
107
|
+
1. **Options Deserialization:** Use **`serde-wasm-bindgen`** to safely convert the incoming `JsValue` (the options object) into a **`CodegenOptions`** Rust struct for internal type safety.
|
|
108
|
+
2. **Naga Reflection:** The core logic uses **`naga`** to parse the GLSL and analyze the Intermediate Representation (IR). This analysis extracts:
|
|
109
|
+
* All **Uniform** names, types, and locations.
|
|
110
|
+
* All **Attribute** names and types.
|
|
111
|
+
* All **Texture/Sampler** definitions.
|
|
112
|
+
3. **JavaScript Generation:** Use the reflection data to programmatically generate the user-facing JavaScript class string, including:
|
|
113
|
+
* Class definition (`class MyKernel { ... }`).
|
|
114
|
+
* **Typed Setter Methods** (e.g., `setUniformFloat(name, value)`).
|
|
115
|
+
* WASM calls to Component 1's low-level `buffer_data`, `uniform_1f`, etc., methods.
|
|
116
|
+
4. **Structured Output (Codec):** Build the final **`GeneratedOutput`** struct, which uses **`#[wasm_bindgen]`** to ensure clean object transfer:
|
|
117
|
+
* `kernel_code`: The generated JavaScript class string.
|
|
118
|
+
* `metadata`: Array of objects detailing the introspected resources.
|
|
119
|
+
* `diagnostics`: Array of objects containing warnings and errors from `naga` and custom checks.
|
|
120
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# WebGL Emulator (Component 1) Deep Dive
|
|
2
|
+
|
|
3
|
+
The **WebGL Emulator** is the **pure-Rust software graphics driver** that compiles to a single, single-threaded WASM module. Its primary goal is **correctness, fidelity, and debuggability** by mimicking the entire WebGL2 state machine and rendering pipeline on the CPU.
|
|
4
|
+
|
|
5
|
+
## 1. ⚙️ Core Architecture and State Management
|
|
6
|
+
|
|
7
|
+
The emulator's design centers on satisfying the **`glow::Context` trait** while managing all resources within the WASM linear memory.
|
|
8
|
+
|
|
9
|
+
* **Factory Function:** The entire system is instantiated via the clean factory function: `createGLContext(width, height)`. This function initializes the full internal state and returns a handle.
|
|
10
|
+
* **State Container:** The central struct, e.g., `WasmGLContext`, is the single source of truth for the entire GL state. It manages:
|
|
11
|
+
* **Resource Registry (`hashbrown::HashMap<u32, ResourceData>`):** Maps the user-facing $\mathbf{u32}$ integer handles (returned by `gl.createBuffer()`, etc.) to the actual Rust structs holding the data and parameters.
|
|
12
|
+
* **Framebuffer:** A large `Vec<u32>` or `Vec<u8>` in the WASM heap that stores the final pixel output.
|
|
13
|
+
* **Bound State:** Fields tracking the currently bound program, active VAO, active texture unit, viewport dimensions, etc.
|
|
14
|
+
|
|
15
|
+
## 2. 🔌 Implementing the $\mathbf{300+}$ API Surface with `glow`
|
|
16
|
+
|
|
17
|
+
This step minimizes bug surface by reusing the `glow` API definition.
|
|
18
|
+
|
|
19
|
+
* **Trait Implementation:** The `WasmGLContext` struct implements every method defined in the `glow::Context` trait.
|
|
20
|
+
* **Stubbing:** Approximately $\mathbf{80\%}$ of the methods implement simple state updates or stubs:
|
|
21
|
+
* **State Setting:** Methods like `enable(DEPTH_TEST)` simply flip a boolean in the `WasmGLContext` struct.
|
|
22
|
+
* **Resource Binding:** Methods like `bind_buffer(ARRAY_BUFFER, handle)` update the state machine's field to hold the input $\mathbf{u32}$ handle.
|
|
23
|
+
* **Unsupported Features:** Methods for complex GPU features like `begin_query` or `fence_sync` are implemented as **no-ops** (stubs), returning success without affecting internal state, as they are non-goals for a unit-testing platform.
|
|
24
|
+
* **Data Transfer (`buffer_data`):** The body of this function handles the vital **transactional copy** of `TypedArray` data from JavaScript into the WASM heap buffer referenced by the `u32` handle, ensuring data integrity within the emulation.
|
|
25
|
+
|
|
26
|
+
## 3. 🧠 The Complex Core: Shader Translation and Execution
|
|
27
|
+
|
|
28
|
+
The most bespoke and critical logic is transforming the GLSL source into executable Rust code.
|
|
29
|
+
|
|
30
|
+
### A. Shader Compilation Flow (`compile_shader` / `link_program`)
|
|
31
|
+
|
|
32
|
+
1. **Parse & Reflect:** The `shader_source()` and `compile_shader()` methods feed the GLSL code into **`naga`**.
|
|
33
|
+
* **Naga Output:** `naga` performs parsing, validation, and produces its **Intermediate Representation (IR)**.
|
|
34
|
+
2. **Code Generation (IR $\rightarrow$ Rust):** A custom routine is required to traverse the Naga IR and output a **Rust source code string** that accurately replicates the shader's logic.
|
|
35
|
+
* **Vertex Kernel:** Generates a Rust function signature like `fn vs_kernel(uniforms: &Uniforms, vertex_in: &VertexIn) -> VertexOut`, where `VertexIn` and `VertexOut` are structs derived from the shader's attributes and varyings.
|
|
36
|
+
* **Fragment Kernel:** Generates a Rust function signature like `fn fs_kernel(uniforms: &Uniforms, fragment_in: &FragmentIn) -> Color`, implementing all shading logic.
|
|
37
|
+
3. **Kernel Storage:** The Rust source code is compiled (or dynamically built/cached), and a **function pointer or closure** to this executable kernel is stored in the internal `ProgramData` resource.
|
|
38
|
+
|
|
39
|
+
### B. Software Rasterizer Execution (`draw_arrays` and similar)
|
|
40
|
+
|
|
41
|
+
The `draw_arrays()` call initiates the CPU-bound process:
|
|
42
|
+
|
|
43
|
+
1. **Vertex Execution:** The emulation loop iterates through the vertex data. For each vertex, it calls the **Vertex Kernel (Rust function)**, which performs the vertex transformation using **`glam`** math and outputs the clip-space coordinates.
|
|
44
|
+
2. **Rasterization:** The **`glam`**-powered core logic handles triangle setup, clipping, barycentric interpolation of varyings, and determining which pixels are covered.
|
|
45
|
+
3. **Fragment Execution:** For every covered pixel, the loop calls the **Fragment Kernel (Rust function)**, passing the interpolated varyings and uniform data. This executes the final shading calculation.
|
|
46
|
+
4. **Output Merger:** Applies depth, stencil, and blending logic based on the current state before writing the final color result to the **WASM Framebuffer**.
|
|
47
|
+
|
|
48
|
+
## 4. 🔬 Debugging and Output
|
|
49
|
+
|
|
50
|
+
* **Debugging Hooks:** The structure of the generated **Rust CPU Kernels** is explicitly designed to be inspected by WASM debugging tools (like browser DevTools). Because the GLSL is translated into traceable Rust code, the developer can pause execution inside the shader logic.
|
|
51
|
+
* **Final Output:** The separate `presentFrame()` function acts as the single bridge to the host, copying the contents of the **WASM Framebuffer** to a JavaScript `Uint8Array` for display via `ctx.putImageData()`.
|
package/package.json
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webgl2",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "WebGL2 tools to derisk large GPU projects on the web beyond toys and demos.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
8
|
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/mavity/mavity"
|
|
12
|
+
},
|
|
9
13
|
"keywords": [],
|
|
10
14
|
"author": "",
|
|
11
|
-
"license": "
|
|
15
|
+
"license": "TBD",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/mavity/mavity/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/mavity/mavity#readme"
|
|
12
20
|
}
|