progpu-renderer 0.1.0-preview.1
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/LICENSE +21 -0
- package/README.md +97 -0
- package/THIRD-PARTY-NOTICES.md +22 -0
- package/build-info.json +20 -0
- package/index.d.ts +91 -0
- package/index.js +158 -0
- package/licenses/emdawnwebgpu/webgpu/src/LICENSE +68 -0
- package/licenses/emdawnwebgpu/webgpu_cpp/LICENSE +26 -0
- package/licenses/emscripten/LICENSE +102 -0
- package/licenses/emscripten/system/lib/compiler-rt/LICENSE.TXT +311 -0
- package/licenses/emscripten/system/lib/libc/musl/COPYRIGHT +193 -0
- package/licenses/emscripten/system/lib/libcxx/LICENSE.TXT +311 -0
- package/licenses/emscripten/system/lib/libcxxabi/LICENSE.TXT +311 -0
- package/licenses/emscripten/system/lib/libunwind/LICENSE.TXT +311 -0
- package/licenses/emscripten/system/lib/llvm-libc/LICENSE.TXT +278 -0
- package/licenses/emscripten/system/lib/mimalloc/LICENSE +21 -0
- package/package.json +29 -0
- package/progpu-native.mjs +2 -0
- package/progpu-native.wasm +0 -0
- package/scene.js +205 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wiesław Šoltés
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# ProGPU for JavaScript
|
|
2
|
+
|
|
3
|
+
An ES-module library using ProGPU's retained C++ vector renderer, compiled to
|
|
4
|
+
WebAssembly and running on WebGPU. No .NET installation or global Module object
|
|
5
|
+
is required. A browser with WebGPU and a secure origin (HTTPS or localhost) is
|
|
6
|
+
required; there is no Canvas2D, WebGL, or software-renderer fallback.
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
import { createRenderer, SceneBuilder, Path } from 'progpu-renderer';
|
|
10
|
+
|
|
11
|
+
const canvas = document.querySelector('canvas');
|
|
12
|
+
const renderer = await createRenderer({ canvas });
|
|
13
|
+
renderer.resize({ width: 640, height: 360, pixelRatio: Math.max(1, Math.min(4, devicePixelRatio)) });
|
|
14
|
+
|
|
15
|
+
const curve = new Path()
|
|
16
|
+
.moveTo(80, 160)
|
|
17
|
+
.cubicTo(80, 20, 280, 20, 280, 160)
|
|
18
|
+
.lineTo(80, 160)
|
|
19
|
+
.close();
|
|
20
|
+
const scene = new SceneBuilder({ sceneId: 1n, generation: 1n })
|
|
21
|
+
.fillRect(20, 20, 40, 40, [1, 0.2, 0.1, 1])
|
|
22
|
+
.fillPath(curve, [0.1, 0.5, 1, 1])
|
|
23
|
+
.build();
|
|
24
|
+
|
|
25
|
+
renderer.updateScene(scene); // Only when the immutable scene changes.
|
|
26
|
+
renderer.render({ clearColor: [0.06, 0.06, 0.08, 1] });
|
|
27
|
+
// Keep the renderer for subsequent frames. It does not install an animation loop.
|
|
28
|
+
// renderer.dispose(); // When the view is permanently removed.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Use your application's requestAnimationFrame scheduling for animated views.
|
|
32
|
+
Call `resize` when the logical size or device-pixel ratio changes. Geometry
|
|
33
|
+
coordinates are logical pixels; colors are RGBA values between zero and one.
|
|
34
|
+
Paths preserve line, quadratic and cubic segments through the native renderer.
|
|
35
|
+
|
|
36
|
+
## Packaging and assets
|
|
37
|
+
|
|
38
|
+
The archive includes its JavaScript modules, TypeScript declarations, generated
|
|
39
|
+
`progpu-native.mjs`, and `progpu-native.wasm`. Serve the Wasm file alongside the
|
|
40
|
+
generated module. Bundlers must copy/preserve that asset URL; check the emitted
|
|
41
|
+
network request rather than treating a successful JavaScript build as proof that
|
|
42
|
+
Wasm was deployed. `progpu-renderer/progpu-native.wasm` is an exported asset subpath.
|
|
43
|
+
For unbundled use, map the bare `progpu-renderer` specifier to the installed `index.js`
|
|
44
|
+
with an import map. Node.js can inspect/pack the library, but is not a supported
|
|
45
|
+
WebGPU rendering host for this browser build.
|
|
46
|
+
|
|
47
|
+
This source tree is packaged by `eng/progpu-pack-npm.mjs`; it is not itself a
|
|
48
|
+
complete publishable archive until the native target has been built and staged.
|
|
49
|
+
PR builds never receive a publishing token. The separate manual release workflow
|
|
50
|
+
uses the repository's `NPM_TOKEN` only for the final publish step after verifying
|
|
51
|
+
the successful Build, merged source commit and exact archive digest. Prereleases
|
|
52
|
+
use the `next` distribution tag. There is no install or publish lifecycle script.
|
|
53
|
+
|
|
54
|
+
## TypeScript
|
|
55
|
+
|
|
56
|
+
The installed-package declaration gate uses TypeScript 6.0.3 with `strict`,
|
|
57
|
+
`noEmit`, `target: "ES2022"`, `module: "NodeNext"` and `lib: ["ES2022", "DOM"]`.
|
|
58
|
+
The browser DOM declarations supply the real `GPUDevice` type; the package does
|
|
59
|
+
not substitute a reduced device interface or add a runtime typing dependency.
|
|
60
|
+
The same installed consumer was also checked with TypeScript 7.0.2.
|
|
61
|
+
|
|
62
|
+
TypeScript 5 users need the supplemental `@webgpu/types` package and must opt it
|
|
63
|
+
into their compiler's `types` list (verified with TypeScript 5.9.3 and
|
|
64
|
+
`@webgpu/types` 0.1.74). Do not unconditionally include that supplement with newer
|
|
65
|
+
DOM libraries: duplicate WebGPU declarations fail strict compilation. Follow the
|
|
66
|
+
[GPUWeb type package's compatibility guidance](https://github.com/gpuweb/types)
|
|
67
|
+
when selecting a compiler and DOM declaration version.
|
|
68
|
+
|
|
69
|
+
## Ownership and supported authoring
|
|
70
|
+
|
|
71
|
+
`Path` and `SceneBuilder` are mutable authoring objects. Recording a path/brush
|
|
72
|
+
copies its input; `build()` returns an immutable scene snapshot. Use a new
|
|
73
|
+
generation for changed content with an existing scene ID. Stable frames reuse
|
|
74
|
+
the accepted native scene instead of crossing into Wasm per drawing command.
|
|
75
|
+
|
|
76
|
+
The typed authoring surface includes solid/linear-gradient fills, nonzero and
|
|
77
|
+
even-odd curved paths, connected polyline strokes, transforms, rectangular clips,
|
|
78
|
+
opacity state and opacity layers. Text layout, SVG parsing and custom shaders
|
|
79
|
+
are not typed JavaScript authoring APIs in this preview. They are not silently
|
|
80
|
+
approximated.
|
|
81
|
+
|
|
82
|
+
Advanced integrations may supply an existing complete native semantic stream as
|
|
83
|
+
a Uint8Array to `updateScene`. It goes through the same native validation and
|
|
84
|
+
compiler as other ProGPU hosts. `getSceneStream()` returns an owned copy of the
|
|
85
|
+
currently accepted stream; modifying that copy cannot mutate the renderer.
|
|
86
|
+
The exported native module is a low-level, versioned ABI, not a promise that raw
|
|
87
|
+
native pointers or wire layouts are stable across package versions.
|
|
88
|
+
|
|
89
|
+
Each factory creates an isolated Wasm module and renderer. Pass `{ canvas, device }`
|
|
90
|
+
to borrow an existing WebGPU device; `dispose()` never destroys a supplied device.
|
|
91
|
+
The device must remain live while the renderer is used. Device errors remain
|
|
92
|
+
explicit; disposal is not automatic recovery or permission to reconfigure a
|
|
93
|
+
borrowed device. Runtime-owned handles are released through the native engine.
|
|
94
|
+
|
|
95
|
+
See `build-info.json`, LICENSE and THIRD-PARTY-NOTICES.md for exact source,
|
|
96
|
+
toolchain and runtime notices. CI's installed-package browser checks are bounded
|
|
97
|
+
rendering/ownership checks, not a claim of complete third-party engine integration.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Runtime notices
|
|
2
|
+
|
|
3
|
+
ProGPU's original renderer and JavaScript adapter are MIT licensed; see LICENSE.
|
|
4
|
+
The generated JavaScript and WebAssembly also contain the Emscripten runtime,
|
|
5
|
+
C/C++ standard-library runtime, and Emdawnwebgpu browser bindings.
|
|
6
|
+
|
|
7
|
+
The package build copies original notices from the actual pinned Emscripten
|
|
8
|
+
4.0.18 toolchain and its hash-verified Emdawnwebgpu port into `licenses/`.
|
|
9
|
+
`build-info.json` records their file hashes and the exact ProGPU source commit.
|
|
10
|
+
Notices are retained in full; some toolchain notices cover optional runtime
|
|
11
|
+
components which this package does not use.
|
|
12
|
+
|
|
13
|
+
No font files, third-party renderer implementations, Chromium, Playwright,
|
|
14
|
+
native operating-system libraries, .NET runtime, or NuGet packages are included.
|
|
15
|
+
|
|
16
|
+
Toolchain references:
|
|
17
|
+
|
|
18
|
+
- https://github.com/emscripten-core/emscripten/tree/4.0.18
|
|
19
|
+
- https://github.com/emscripten-core/emscripten/blob/4.0.18/tools/ports/emdawnwebgpu.py
|
|
20
|
+
|
|
21
|
+
The existing pinned Emdawnwebgpu port supplies browser WebGPU ABI bindings.
|
|
22
|
+
It is a declared build dependency, not source copied into ProGPU implementation.
|
package/build-info.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sourceCommit": "bdc27c31e2cdea294790cc0b8e7f66d6ac5961bc",
|
|
3
|
+
"sourceDirty": false,
|
|
4
|
+
"emscripten": "4.0.18",
|
|
5
|
+
"emdawnPortSha256": "119ddcb024a537e5e7afdcbfe3a033a460b2c0bd335dff84552f3e87603eee9c",
|
|
6
|
+
"buildRunId": "36265448220",
|
|
7
|
+
"buildRunAttempt": "1",
|
|
8
|
+
"licenses": {
|
|
9
|
+
"licenses/emscripten/LICENSE": "620a78084fc7ca97c0b5dea9abf891f3ffcadfdbf305276f099c9c4e12fc1d86",
|
|
10
|
+
"licenses/emscripten/system/lib/compiler-rt/LICENSE.TXT": "1a8f1058753f1ba890de984e48f0242a3a5c29a6a8f2ed9fd813f36985387e8d",
|
|
11
|
+
"licenses/emscripten/system/lib/libc/musl/COPYRIGHT": "f9bc4423732350eb0b3f7ed7e91d530298476f8fec0c6c427a1c04ade22655af",
|
|
12
|
+
"licenses/emscripten/system/lib/libcxx/LICENSE.TXT": "539dd7aed86e8a4f12cbdd0e6c50c189c7d74847e4fecc64ce2c6ee3a01da38b",
|
|
13
|
+
"licenses/emscripten/system/lib/libcxxabi/LICENSE.TXT": "e2b35be49f7284a45b7baca8fc7b3ab7440e7902392b2528a457816b5bb2a15c",
|
|
14
|
+
"licenses/emscripten/system/lib/libunwind/LICENSE.TXT": "b5efebcaca80879234098e52d1725e6d9eb8fb96a19fce625d39184b705f7b6d",
|
|
15
|
+
"licenses/emscripten/system/lib/llvm-libc/LICENSE.TXT": "ebcd9bbf783a73d05c53ba4d586b8d5813dcdf3bbec50265860ccc885e606f47",
|
|
16
|
+
"licenses/emscripten/system/lib/mimalloc/LICENSE": "19c99805e7a44a34b297a75d1edea9985e300066dfc024d5c99d4236d4573b5d",
|
|
17
|
+
"licenses/emdawnwebgpu/webgpu/src/LICENSE": "2f79bf3699b0870251255b381670237f73f21a04a38c094f791eba39c5fd1df7",
|
|
18
|
+
"licenses/emdawnwebgpu/webgpu_cpp/LICENSE": "7e1efc85a78732a13d7ddfc8b52912da7c8f8d3c6d334624b20e3f3a96297de0"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export type Color = readonly [number, number, number, number];
|
|
2
|
+
export type Point = readonly [number, number];
|
|
3
|
+
/** Row-vector affine [m11,m12,m21,m22,m31,m32]. */
|
|
4
|
+
export type Transform = readonly [number, number, number, number, number, number];
|
|
5
|
+
export type Rect = readonly [number, number, number, number];
|
|
6
|
+
export interface LinearGradient {
|
|
7
|
+
readonly type: 'linearGradient';
|
|
8
|
+
readonly start: Point;
|
|
9
|
+
readonly end: Point;
|
|
10
|
+
readonly stops: readonly {readonly offset: number; readonly color: Color}[];
|
|
11
|
+
readonly opacity?: number;
|
|
12
|
+
readonly spread?: 'pad' | 'reflect' | 'repeat';
|
|
13
|
+
}
|
|
14
|
+
export type Brush = Color | LinearGradient;
|
|
15
|
+
export type StrokeCap = 'flat' | 'square' | 'round' | 'triangle';
|
|
16
|
+
export type StrokeJoin = 'miter' | 'bevel' | 'round';
|
|
17
|
+
export interface StrokeOptions {
|
|
18
|
+
width?: number; closed?: boolean; startCap?: StrokeCap; endCap?: StrokeCap;
|
|
19
|
+
lineJoin?: StrokeJoin; dashCap?: StrokeCap; miterLimit?: number;
|
|
20
|
+
/** Alternating on/off thickness multipliers; odd counts repeat. */
|
|
21
|
+
dashes?: readonly number[];
|
|
22
|
+
dashOffset?: number; transform?: Transform;
|
|
23
|
+
}
|
|
24
|
+
export class Path {
|
|
25
|
+
constructor();
|
|
26
|
+
moveTo(x: number, y: number): this;
|
|
27
|
+
lineTo(x: number, y: number): this;
|
|
28
|
+
quadraticTo(cx: number, cy: number, x: number, y: number): this;
|
|
29
|
+
cubicTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): this;
|
|
30
|
+
close(): this;
|
|
31
|
+
}
|
|
32
|
+
export class Scene {
|
|
33
|
+
private constructor();
|
|
34
|
+
readonly sceneId: bigint;
|
|
35
|
+
readonly generation: bigint;
|
|
36
|
+
}
|
|
37
|
+
export class SceneBuilder {
|
|
38
|
+
constructor(options?: {sceneId?: bigint; generation?: bigint});
|
|
39
|
+
fillRect(x: number, y: number, width: number, height: number, brush: Brush, options?: {transform?: Transform}): this;
|
|
40
|
+
fillPath(path: Path, brush: Brush, options?: {fillRule?: 'nonzero' | 'evenodd'; transform?: Transform}): this;
|
|
41
|
+
strokePolyline(points: readonly Point[], brush: Brush, options?: StrokeOptions): this;
|
|
42
|
+
/** Absolute transform/opacity. clipRect is in logical target coordinates. */
|
|
43
|
+
save(options?: {transform?: Transform; opacity?: number; clipRect?: Rect}): this;
|
|
44
|
+
restore(): this;
|
|
45
|
+
/** Isolated source-over compositing; opacity is applied once on pop. */
|
|
46
|
+
pushLayer(options?: {opacity?: number; bounds?: Rect}): this;
|
|
47
|
+
popLayer(): this;
|
|
48
|
+
/** Snapshots authoring data; unbalanced scopes are rejected. */
|
|
49
|
+
build(): Scene;
|
|
50
|
+
}
|
|
51
|
+
export interface SceneUpdateMetrics {
|
|
52
|
+
readonly sceneId: bigint; readonly generation: bigint;
|
|
53
|
+
readonly commandCount: number; readonly resourceCount: number;
|
|
54
|
+
readonly streamBytes: number; readonly snapshotReused: boolean;
|
|
55
|
+
readonly drawCount: number; readonly payloadBytes: number;
|
|
56
|
+
}
|
|
57
|
+
export interface FrameMetrics {
|
|
58
|
+
readonly commandCount: number; readonly drawCallCount: number; readonly familySwitchCount: number;
|
|
59
|
+
readonly submissionCount: bigint; readonly payloadHash: bigint;
|
|
60
|
+
readonly vertexUploadBytes: number; readonly indexUploadBytes: number;
|
|
61
|
+
readonly textureUploadBytes: number; readonly uniformUploadBytes: number;
|
|
62
|
+
readonly coverageStagingBytes: number; readonly brushUploadBytes: number;
|
|
63
|
+
readonly gradientStopUploadBytes: number; readonly textStyleUploadBytes: number;
|
|
64
|
+
readonly colorGlyphUploadBytes: number;
|
|
65
|
+
}
|
|
66
|
+
export interface CanvasMetrics {
|
|
67
|
+
readonly width: number; readonly height: number;
|
|
68
|
+
readonly logicalWidth: number; readonly logicalHeight: number; readonly scale: number;
|
|
69
|
+
}
|
|
70
|
+
export interface Renderer {
|
|
71
|
+
readonly device: GPUDevice;
|
|
72
|
+
readonly error: Error | null;
|
|
73
|
+
/** Logical extent with explicit physical-pixel scale (1..4). */
|
|
74
|
+
resize(options: {width: number; height: number; pixelRatio?: number}): CanvasMetrics;
|
|
75
|
+
/** One changed immutable generation, or a complete native stream. */
|
|
76
|
+
updateScene(scene: Scene | Uint8Array): SceneUpdateMetrics;
|
|
77
|
+
/** Independent copy of the last accepted full native stream. */
|
|
78
|
+
getSceneStream(): Uint8Array;
|
|
79
|
+
/** Submits GPU work; return is not a GPU/display completion fence. */
|
|
80
|
+
render(options?: {clearColor?: Color}): FrameMetrics;
|
|
81
|
+
/** Idempotent. Never destroys a caller-supplied GPUDevice. */
|
|
82
|
+
dispose(): void;
|
|
83
|
+
}
|
|
84
|
+
/** Browser DOM + WebGPU only; no Canvas2D/WebGL/software renderer fallback.
|
|
85
|
+
* The caller owns requestAnimationFrame, CSS sizing and resize notifications.
|
|
86
|
+
* TypeScript 6+ DOM declarations provide GPUDevice. TypeScript 5 consumers must
|
|
87
|
+
* explicitly enable supplemental @webgpu/types; do not mix those declarations
|
|
88
|
+
* with newer DOM libraries that already define WebGPU. */
|
|
89
|
+
export function createRenderer(options: {
|
|
90
|
+
canvas: HTMLCanvasElement; device?: GPUDevice; onError?: (error: Error) => void;
|
|
91
|
+
}): Promise<Renderer>;
|
package/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {Scene, SceneBuilder, Path, scenePacket} from './scene.js';
|
|
2
|
+
export {Scene, SceneBuilder, Path};
|
|
3
|
+
|
|
4
|
+
const canvasOwners = new WeakSet();
|
|
5
|
+
|
|
6
|
+
// Construct this callback outside createRenderer's lexical environment. A
|
|
7
|
+
// pending borrowed-device promise must retain only the detachable token, not
|
|
8
|
+
// the factory's canvas, module, renderer methods or other closed-over state.
|
|
9
|
+
function deviceLossCallback(lifetime) {
|
|
10
|
+
return (info) => lifetime.report?.(new Error(`WebGPU device lost (${info.reason}): ${info.message}`));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** One isolated native module/renderer. No DOM work or GPU initialization occurs
|
|
14
|
+
* on import. The application owns its animation loop and resize policy. */
|
|
15
|
+
export async function createRenderer({canvas, device: suppliedDevice, onError} = {}) {
|
|
16
|
+
if (typeof HTMLCanvasElement === 'undefined' || !(canvas instanceof HTMLCanvasElement) ||
|
|
17
|
+
!canvas.isConnected || canvas.ownerDocument !== document)
|
|
18
|
+
throw new TypeError('canvas must be a connected HTMLCanvasElement in the current document');
|
|
19
|
+
if (!globalThis.navigator?.gpu) throw new Error('WebGPU is unavailable');
|
|
20
|
+
if (canvasOwners.has(canvas) || canvas.hasAttribute('data-progpu-renderer'))
|
|
21
|
+
throw new Error('The canvas already has a ProGPU renderer');
|
|
22
|
+
if (onError !== undefined && typeof onError !== 'function') throw new TypeError('onError must be a function');
|
|
23
|
+
|
|
24
|
+
canvasOwners.add(canvas);
|
|
25
|
+
const marker = crypto.randomUUID();
|
|
26
|
+
canvas.setAttribute('data-progpu-renderer', marker);
|
|
27
|
+
let device = suppliedDevice, module, disposed = false, initialized = false;
|
|
28
|
+
let failure = null, listener = null, metricsPointer = 0, errorPointer = 0;
|
|
29
|
+
let currentScene = null, updateMetrics = null;
|
|
30
|
+
const lifetime = {report: null};
|
|
31
|
+
function report(error) {
|
|
32
|
+
if (disposed || failure) return;
|
|
33
|
+
failure = error;
|
|
34
|
+
if (initialized) module._progpu_browser_device_lost();
|
|
35
|
+
if (onError) onError(error);
|
|
36
|
+
}
|
|
37
|
+
lifetime.report = report;
|
|
38
|
+
function check() {
|
|
39
|
+
if (disposed) throw new Error('Renderer is disposed');
|
|
40
|
+
if (failure) throw failure;
|
|
41
|
+
if (!canvas.isConnected || canvas.getAttribute('data-progpu-renderer') !== marker)
|
|
42
|
+
throw new Error('The renderer canvas was removed or its ownership marker changed');
|
|
43
|
+
}
|
|
44
|
+
function nativeCheck(success) {
|
|
45
|
+
if (success) return;
|
|
46
|
+
const heap = module.HEAPU8;
|
|
47
|
+
let end = errorPointer;
|
|
48
|
+
while (end < errorPointer + 1024 && heap[end] !== 0) ++end;
|
|
49
|
+
throw new Error(new TextDecoder().decode(heap.subarray(errorPointer, end)) || 'Native renderer operation failed');
|
|
50
|
+
}
|
|
51
|
+
function withBytes(bytes, call) {
|
|
52
|
+
const pointer = module._malloc(bytes.byteLength);
|
|
53
|
+
if (!pointer) throw new Error('Native transport allocation failed');
|
|
54
|
+
try { module.HEAPU8.set(bytes, pointer); return call(pointer); }
|
|
55
|
+
finally { module._free(pointer); }
|
|
56
|
+
}
|
|
57
|
+
function word(index) { return new DataView(module.HEAPU8.buffer).getBigUint64(metricsPointer + index * 8, true); }
|
|
58
|
+
function count(index) { return Number(word(index)); }
|
|
59
|
+
function resize({width, height, pixelRatio = Math.max(1, Math.min(4, globalThis.devicePixelRatio || 1))}) {
|
|
60
|
+
check();
|
|
61
|
+
for (const value of [width, height, pixelRatio])
|
|
62
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) throw new RangeError('Canvas dimensions and pixel ratio must be positive and finite');
|
|
63
|
+
if (pixelRatio < 1 || pixelRatio > 4) throw new RangeError('The native browser host supports pixel ratios from one to four');
|
|
64
|
+
const physicalWidth = Math.max(1, Math.round(width * pixelRatio));
|
|
65
|
+
const physicalHeight = Math.max(1, Math.round(height * pixelRatio));
|
|
66
|
+
if (physicalWidth > device.limits.maxTextureDimension2D || physicalHeight > device.limits.maxTextureDimension2D)
|
|
67
|
+
throw new RangeError('Canvas size exceeds this device maxTextureDimension2D');
|
|
68
|
+
const metrics = Object.freeze({width: physicalWidth, height: physicalHeight,
|
|
69
|
+
logicalWidth: width, logicalHeight: height, scale: pixelRatio});
|
|
70
|
+
// Original browser host contract: physical texture dimensions plus a
|
|
71
|
+
// separate logical extent/DPI. Resizing never recompiles the scene.
|
|
72
|
+
if (canvas.width !== physicalWidth) canvas.width = physicalWidth;
|
|
73
|
+
if (canvas.height !== physicalHeight) canvas.height = physicalHeight;
|
|
74
|
+
module.progpuBrowserMetrics = metrics;
|
|
75
|
+
return metrics;
|
|
76
|
+
}
|
|
77
|
+
function dispose() {
|
|
78
|
+
if (disposed) return;
|
|
79
|
+
disposed = true; lifetime.report = null;
|
|
80
|
+
if (listener && device) device.removeEventListener('uncapturederror', listener);
|
|
81
|
+
try { if (initialized) { module._progpu_browser_dispose(); initialized = false; } }
|
|
82
|
+
finally {
|
|
83
|
+
if (!suppliedDevice && device) device.destroy();
|
|
84
|
+
if (canvas.getAttribute('data-progpu-renderer') === marker) canvas.removeAttribute('data-progpu-renderer');
|
|
85
|
+
canvasOwners.delete(canvas); currentScene = null; updateMetrics = null;
|
|
86
|
+
// Break the retained promise/listener chain without touching a
|
|
87
|
+
// borrowed device or leaving a live callback into freed wasm state.
|
|
88
|
+
module = null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
if (!device) {
|
|
93
|
+
const adapter = await navigator.gpu.requestAdapter({powerPreference: 'high-performance'});
|
|
94
|
+
if (!adapter) throw new Error('No WebGPU adapter is available');
|
|
95
|
+
device = await adapter.requestDevice();
|
|
96
|
+
}
|
|
97
|
+
if (typeof device.addEventListener !== 'function' || typeof device.queue?.submit !== 'function')
|
|
98
|
+
throw new TypeError('device must be a GPUDevice');
|
|
99
|
+
listener = (event) => lifetime.report?.(new Error(`WebGPU: ${event.error.message}`));
|
|
100
|
+
device.addEventListener('uncapturederror', listener);
|
|
101
|
+
// The promise captures only the detachable lifetime token, not the
|
|
102
|
+
// renderer/module/device. A borrowed device may long outlive dispose.
|
|
103
|
+
device.lost.then(deviceLossCallback(lifetime));
|
|
104
|
+
const format = navigator.gpu.getPreferredCanvasFormat();
|
|
105
|
+
if (format !== 'rgba8unorm' && format !== 'bgra8unorm') throw new Error(`Unsupported native canvas format: ${format}`);
|
|
106
|
+
const {default: factory} = await import('./progpu-native.mjs');
|
|
107
|
+
module = await factory({canvas, preinitializedWebGPUDevice: device,
|
|
108
|
+
progpuBrowserCanvasFormat: format});
|
|
109
|
+
const rect = canvas.getBoundingClientRect();
|
|
110
|
+
resize({width: Math.max(1, rect.width), height: Math.max(1, rect.height)});
|
|
111
|
+
check();
|
|
112
|
+
const selector = new TextEncoder().encode(`canvas[data-progpu-renderer="${marker}"]\0`);
|
|
113
|
+
errorPointer = module._progpu_browser_error();
|
|
114
|
+
withBytes(selector, (pointer) => nativeCheck(module._progpu_browser_initialize(pointer)));
|
|
115
|
+
initialized = true; metricsPointer = module._progpu_browser_metrics();
|
|
116
|
+
check();
|
|
117
|
+
return Object.freeze({
|
|
118
|
+
device,
|
|
119
|
+
get error() { return failure; },
|
|
120
|
+
resize,
|
|
121
|
+
updateScene(scene) {
|
|
122
|
+
check();
|
|
123
|
+
const packet = scenePacket(scene);
|
|
124
|
+
if (!packet && !(scene instanceof Uint8Array)) throw new TypeError('Expected an immutable Scene or full native stream Uint8Array');
|
|
125
|
+
// A repeated immutable snapshot needs no compilation/crossing.
|
|
126
|
+
// Do not cache caller-owned raw byte arrays by object identity.
|
|
127
|
+
if (packet && scene === currentScene) return updateMetrics;
|
|
128
|
+
const bytes = packet ?? scene;
|
|
129
|
+
if (bytes.byteLength === 0) throw new RangeError('Scene stream must not be empty');
|
|
130
|
+
withBytes(bytes, (pointer) => nativeCheck(module._progpu_browser_update(pointer, bytes.byteLength, packet ? 1 : 0)));
|
|
131
|
+
currentScene = packet ? scene : null;
|
|
132
|
+
updateMetrics = Object.freeze({sceneId: word(0), generation: word(1), commandCount: count(2),
|
|
133
|
+
resourceCount: count(3), streamBytes: count(4), snapshotReused: word(5) !== 0n,
|
|
134
|
+
drawCount: count(6), payloadBytes: count(7)});
|
|
135
|
+
return updateMetrics;
|
|
136
|
+
},
|
|
137
|
+
getSceneStream() {
|
|
138
|
+
check();
|
|
139
|
+
const size = module._progpu_browser_stream_size();
|
|
140
|
+
if (!size) throw new Error('Update a scene before exporting its native stream');
|
|
141
|
+
const pointer = module._progpu_browser_stream();
|
|
142
|
+
return module.HEAPU8.slice(pointer, pointer + size);
|
|
143
|
+
},
|
|
144
|
+
render({clearColor = [0, 0, 0, 0]} = {}) {
|
|
145
|
+
check();
|
|
146
|
+
if (!clearColor || clearColor.length !== 4 || Array.from(clearColor).some((v) => typeof v !== 'number' || !Number.isFinite(v) || v < 0 || v > 1))
|
|
147
|
+
throw new TypeError('clearColor must contain four finite zero-to-one components');
|
|
148
|
+
nativeCheck(module._progpu_browser_render(...clearColor));
|
|
149
|
+
return Object.freeze({commandCount: count(0), drawCallCount: count(1), familySwitchCount: count(2),
|
|
150
|
+
submissionCount: word(3), vertexUploadBytes: count(4), indexUploadBytes: count(5),
|
|
151
|
+
textureUploadBytes: count(6), uniformUploadBytes: count(7), coverageStagingBytes: count(8),
|
|
152
|
+
payloadHash: word(9), brushUploadBytes: count(10), gradientStopUploadBytes: count(11),
|
|
153
|
+
textStyleUploadBytes: count(12), colorGlyphUploadBytes: count(13)});
|
|
154
|
+
},
|
|
155
|
+
dispose,
|
|
156
|
+
});
|
|
157
|
+
} catch (error) { dispose(); throw error; }
|
|
158
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Emscripten is available under 2 licenses, the MIT license and the
|
|
2
|
+
University of Illinois/NCSA Open Source License.
|
|
3
|
+
|
|
4
|
+
Both are permissive open source licenses, with little if any
|
|
5
|
+
practical difference between them.
|
|
6
|
+
|
|
7
|
+
The reason for offering both is that (1) the MIT license is
|
|
8
|
+
well-known, while (2) the University of Illinois/NCSA Open Source
|
|
9
|
+
License allows Emscripten's code to be integrated upstream into
|
|
10
|
+
LLVM, which uses that license, should the opportunity arise.
|
|
11
|
+
|
|
12
|
+
The full text of both licenses follows.
|
|
13
|
+
|
|
14
|
+
==============================================================================
|
|
15
|
+
|
|
16
|
+
Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
|
|
17
|
+
|
|
18
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
19
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
20
|
+
in the Software without restriction, including without limitation the rights
|
|
21
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
22
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
23
|
+
furnished to do so, subject to the following conditions:
|
|
24
|
+
|
|
25
|
+
The above copyright notice and this permission notice shall be included in
|
|
26
|
+
all copies or substantial portions of the Software.
|
|
27
|
+
|
|
28
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
29
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
30
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
31
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
32
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
33
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
34
|
+
THE SOFTWARE.
|
|
35
|
+
|
|
36
|
+
==============================================================================
|
|
37
|
+
|
|
38
|
+
Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
|
|
39
|
+
All rights reserved.
|
|
40
|
+
|
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
42
|
+
copy of this software and associated documentation files (the
|
|
43
|
+
"Software"), to deal with the Software without restriction, including
|
|
44
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
45
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
46
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
47
|
+
the following conditions:
|
|
48
|
+
|
|
49
|
+
Redistributions of source code must retain the above copyright
|
|
50
|
+
notice, this list of conditions and the following disclaimers.
|
|
51
|
+
|
|
52
|
+
Redistributions in binary form must reproduce the above
|
|
53
|
+
copyright notice, this list of conditions and the following disclaimers
|
|
54
|
+
in the documentation and/or other materials provided with the
|
|
55
|
+
distribution.
|
|
56
|
+
|
|
57
|
+
Neither the names of Mozilla,
|
|
58
|
+
nor the names of its contributors may be used to endorse
|
|
59
|
+
or promote products derived from this Software without specific prior
|
|
60
|
+
written permission.
|
|
61
|
+
|
|
62
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
63
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
64
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
65
|
+
IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
66
|
+
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
67
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
68
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Copyright 2017-2025 The Dawn & Tint Authors
|
|
2
|
+
//
|
|
3
|
+
// Redistribution and use in source and binary forms, with or without
|
|
4
|
+
// modification, are permitted provided that the following conditions are met:
|
|
5
|
+
//
|
|
6
|
+
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
7
|
+
// list of conditions and the following disclaimer.
|
|
8
|
+
//
|
|
9
|
+
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
10
|
+
// this list of conditions and the following disclaimer in the documentation
|
|
11
|
+
// and/or other materials provided with the distribution.
|
|
12
|
+
//
|
|
13
|
+
// 3. Neither the name of the copyright holder nor the names of its
|
|
14
|
+
// contributors may be used to endorse or promote products derived from
|
|
15
|
+
// this software without specific prior written permission.
|
|
16
|
+
//
|
|
17
|
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
18
|
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
19
|
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
21
|
+
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
22
|
+
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
23
|
+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
24
|
+
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
25
|
+
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
26
|
+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Emscripten is available under 2 licenses, the MIT license and the
|
|
2
|
+
University of Illinois/NCSA Open Source License.
|
|
3
|
+
|
|
4
|
+
Both are permissive open source licenses, with little if any
|
|
5
|
+
practical difference between them.
|
|
6
|
+
|
|
7
|
+
The reason for offering both is that (1) the MIT license is
|
|
8
|
+
well-known, while (2) the University of Illinois/NCSA Open Source
|
|
9
|
+
License allows Emscripten's code to be integrated upstream into
|
|
10
|
+
LLVM, which uses that license, should the opportunity arise.
|
|
11
|
+
|
|
12
|
+
The full text of both licenses follows.
|
|
13
|
+
|
|
14
|
+
==============================================================================
|
|
15
|
+
|
|
16
|
+
Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
|
|
17
|
+
|
|
18
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
19
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
20
|
+
in the Software without restriction, including without limitation the rights
|
|
21
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
22
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
23
|
+
furnished to do so, subject to the following conditions:
|
|
24
|
+
|
|
25
|
+
The above copyright notice and this permission notice shall be included in
|
|
26
|
+
all copies or substantial portions of the Software.
|
|
27
|
+
|
|
28
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
29
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
30
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
31
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
32
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
33
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
34
|
+
THE SOFTWARE.
|
|
35
|
+
|
|
36
|
+
==============================================================================
|
|
37
|
+
|
|
38
|
+
Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
|
|
39
|
+
All rights reserved.
|
|
40
|
+
|
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
42
|
+
copy of this software and associated documentation files (the
|
|
43
|
+
"Software"), to deal with the Software without restriction, including
|
|
44
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
45
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
46
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
47
|
+
the following conditions:
|
|
48
|
+
|
|
49
|
+
Redistributions of source code must retain the above copyright
|
|
50
|
+
notice, this list of conditions and the following disclaimers.
|
|
51
|
+
|
|
52
|
+
Redistributions in binary form must reproduce the above
|
|
53
|
+
copyright notice, this list of conditions and the following disclaimers
|
|
54
|
+
in the documentation and/or other materials provided with the
|
|
55
|
+
distribution.
|
|
56
|
+
|
|
57
|
+
Neither the names of Mozilla,
|
|
58
|
+
nor the names of its contributors may be used to endorse
|
|
59
|
+
or promote products derived from this Software without specific prior
|
|
60
|
+
written permission.
|
|
61
|
+
|
|
62
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
63
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
64
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
65
|
+
IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
66
|
+
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
67
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
68
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
|
|
69
|
+
|
|
70
|
+
==============================================================================
|
|
71
|
+
|
|
72
|
+
This program uses portions of Node.js source code located in src/library_path.js,
|
|
73
|
+
in accordance with the terms of the MIT license. Node's license follows:
|
|
74
|
+
|
|
75
|
+
"""
|
|
76
|
+
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
77
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
78
|
+
of this software and associated documentation files (the "Software"), to
|
|
79
|
+
deal in the Software without restriction, including without limitation the
|
|
80
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
81
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
|
82
|
+
furnished to do so, subject to the following conditions:
|
|
83
|
+
|
|
84
|
+
The above copyright notice and this permission notice shall be included in
|
|
85
|
+
all copies or substantial portions of the Software.
|
|
86
|
+
|
|
87
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
88
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
89
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
90
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
91
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
93
|
+
IN THE SOFTWARE.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
The musl libc project is bundled in this repo, and it has the MIT license, see
|
|
97
|
+
system/lib/libc/musl/COPYRIGHT
|
|
98
|
+
|
|
99
|
+
The third_party/ subdirectory contains code with other licenses. None of it is
|
|
100
|
+
used by default, but certain options use it (e.g., the optional closure compiler
|
|
101
|
+
flag will run closure compiler from third_party/).
|
|
102
|
+
|