onejs-sl 0.1.0 → 0.1.2
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/CHANGELOG.md +20 -0
- package/README.md +96 -7
- package/goldens/goldens.json +480 -0
- package/lib/common.hlsl +155 -0
- package/lib/noise2d.hlsl +167 -0
- package/lib/sdf2d.hlsl +510 -0
- package/package.json +9 -3
- package/src/body.ts +243 -0
- package/src/core.ts +1 -1
- package/src/emit/hlsl-body.ts +7 -0
- package/src/encode.ts +3 -24
- package/src/hlsl.ts +34 -143
- package/src/ir.ts +49 -2
- package/src/lang/lower.ts +6 -3
- package/src/lib/glsl.ts +899 -0
- package/src/lib/hlsl.ts +891 -0
- package/src/lib/index.ts +47 -0
- package/src/lib/table.ts +125 -0
- package/src/lib/types.ts +23 -0
- package/src/lib/wgsl.ts +994 -0
- package/src/serial.ts +3 -1
- package/src/shapes.ts +4 -4
- package/src/sl.ts +27 -1
- package/src/web.ts +53 -28
- package/src/weblib.ts +0 -1303
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.2
|
|
4
|
+
|
|
5
|
+
The helper library has one source, `lib/*.hlsl`, translated at build time into GLSL ES, WGSL and the shared subset and copied into OneJS as its `.cginc` files. The web draws exactly what it drew; the Unity shader's text changes where Metal needed it to, and draws the same.
|
|
6
|
+
|
|
7
|
+
- `emitLibrary` prints the library functions a body calls, in the shared subset
|
|
8
|
+
- `emitBody` prints no scalar swizzles, and types every literal and scalar it passes to an intrinsic
|
|
9
|
+
- `atan2` of vectors is refused; no web backend compiled it
|
|
10
|
+
- `onejs-sl/goldens.json` exports the goldens
|
|
11
|
+
- The tests compile the shared subset as Metal on a Mac with Xcode
|
|
12
|
+
|
|
13
|
+
## 0.1.1
|
|
14
|
+
|
|
15
|
+
A host can now supply its own frame for a program's body and get goldens for the pictures it should draw. Nothing an existing program draws changes, and OneJS's generated Unity shader is byte for byte what 0.1.0 printed.
|
|
16
|
+
|
|
17
|
+
- `onejs-sl/emit/hlsl-body`: `emitBody` and `BodyTarget`, the body in the HLSL and Metal shared subset
|
|
18
|
+
- The Unity shader is printed through `emitBody`
|
|
19
|
+
- `UniformDecl.colour` marks a uniform with a hex default, and `sl.uniform.colour` declares one
|
|
20
|
+
- `inputsUsed` lists the inputs a program reads
|
|
21
|
+
- `goldens/goldens.json`: every corpus fixture as a Linear game stores it, drawn by `npm run goldens`
|
|
22
|
+
|
|
3
23
|
## 0.1.0
|
|
4
24
|
|
|
5
25
|
The shader language compiler as its own package, moved out of `onejs-unity` with its history and its tests. It behaves exactly as `onejs-unity` 0.5.15's `sl` did, at IR version 2 and VM wire version 2.
|
package/README.md
CHANGED
|
@@ -40,11 +40,100 @@ only what it calls.
|
|
|
40
40
|
| `onejs-sl/tables` | `BUILTINS`, `SL_HLSL`, `INPUTS`, `SL_SDF_SHAPES`, `SL_SDF_PARAMS`: what completion and highlighting read |
|
|
41
41
|
| `onejs-sl/limits` | `vmFit(program)`: whether the VM runs it, and why not, without encoding |
|
|
42
42
|
| `onejs-sl/vm` | `encode`, `SL_WIRE_VERSION` |
|
|
43
|
-
| `onejs-sl/emit/
|
|
43
|
+
| `onejs-sl/emit/hlsl-body` | `emitBody`: a program as a function body for a host's own frame; `emitLibrary`: the library functions it calls |
|
|
44
|
+
| `onejs-sl/emit/unity` | `emitShader`: the `.shader` a Unity editor generates, a frame over `emitBody` |
|
|
44
45
|
| `onejs-sl/emit/web` | `emitWGSL`, `emitGLSL`: OneJS's web frame |
|
|
46
|
+
| `onejs-sl/goldens.json` | the goldens (below), as data |
|
|
45
47
|
|
|
46
48
|
`src/entries.test.ts` pins every name, since removing one breaks a host.
|
|
47
49
|
|
|
50
|
+
## A host's own frame: `emitBody`
|
|
51
|
+
|
|
52
|
+
`emitBody(program, target)` prints the body only: one local per node, in the
|
|
53
|
+
HLSL and Metal shared subset (HLSL spelling, `fmod`, no `mul`, no `static`, no
|
|
54
|
+
derivatives, no swizzle of a scalar, and every literal and scalar in an
|
|
55
|
+
intrinsic at its exact type, since Metal overloads where HLSL converts). The `BodyTarget` says what differs between hosts: an expression
|
|
56
|
+
for each input, the float4 holding a uniform slot, a texture sample, whether
|
|
57
|
+
`toLinear` is real (`colour: "linear"`) or the identity (`"gamma"`), and
|
|
58
|
+
optionally a local to assign the result to. It returns the uniform and texture
|
|
59
|
+
slots the body uses and the library functions it calls. OneJS's Unity shader is
|
|
60
|
+
one frame over it (`hlsl.ts`); Magerie's compute kernel is another, and its
|
|
61
|
+
target is in `src/body.test.ts` so an opcode cannot change without the text
|
|
62
|
+
Magerie compiles changing in front of a test.
|
|
63
|
+
|
|
64
|
+
`emitLibrary(body.uses.helpers, colour)` prints the library functions the body
|
|
65
|
+
calls, and everything they call, in the same subset and dependency order, with
|
|
66
|
+
the colour branch asked for: the text a host puts ahead of its frame. It is a
|
|
67
|
+
separate call because OneJS's own frame never needs it (the Unity shader
|
|
68
|
+
includes `SLCommon.cginc`), and a bundle that prints only Unity shaders should
|
|
69
|
+
not carry the library too. On a Mac with Xcode, `src/metal.test.ts` compiles
|
|
70
|
+
the whole library and a body for every corpus program and every builtin at
|
|
71
|
+
every width as Metal, behind the two defines a host's compatibility header
|
|
72
|
+
supplies (`frac`, `lerp`).
|
|
73
|
+
|
|
74
|
+
A uniform declared with a hex default (`uniform float4 tint = #ff8040;`), or
|
|
75
|
+
with `sl.uniform.colour`, is marked `colour: true`: its value is sRGB as
|
|
76
|
+
written, which is what a colour picker shows, and its reads convert. `inputsUsed`
|
|
77
|
+
says which inputs the result depends on, dead nodes aside, so a host knows
|
|
78
|
+
whether a program animates.
|
|
79
|
+
|
|
80
|
+
## The helper library: one source
|
|
81
|
+
|
|
82
|
+
Value and simplex noise, the octave kinds, voronoi, hsv2rgb, `toLinear` and the
|
|
83
|
+
42 distance shapes are written once, in HLSL, in `lib/sdf2d.hlsl`,
|
|
84
|
+
`lib/noise2d.hlsl` and `lib/common.hlsl`. Everything else is printed from them
|
|
85
|
+
by `npm run lib`, and nobody edits the copies:
|
|
86
|
+
|
|
87
|
+
- **OneJS's `.cginc` files** (`SDF2D`, `Noise2D`, `SLCommon` in
|
|
88
|
+
`Resources/OneJS/`) are the source with an include guard and a generated
|
|
89
|
+
header around it. The VM, the generated Unity shaders and `fx` include them.
|
|
90
|
+
`npm run lib` writes them when the package sits in the OneJS container.
|
|
91
|
+
- **`src/lib/`**: `table.ts` (every function, its signature, what it calls, and
|
|
92
|
+
the shape table read from `sl_sdfDistance`'s switch), and the text of each
|
|
93
|
+
function as GLSL ES (`glsl.ts`), WGSL (`wgsl.ts`) and the shared subset
|
|
94
|
+
(`hlsl.ts`). The web emitters and `emitLibrary` take only what a program calls.
|
|
95
|
+
|
|
96
|
+
`lib/translate.ts` does the printing, at build time only. It reads a subset of
|
|
97
|
+
HLSL, listed at its top (functions, locals, `if`, bounded `for`, `switch`,
|
|
98
|
+
intrinsics, `mul(v, float2x2(...))`, and one preprocessor switch,
|
|
99
|
+
`UNITY_COLORSPACE_GAMMA`, which becomes the target's colour), and anything
|
|
100
|
+
outside it is an error with a file and line rather than a guess. HLSL converts
|
|
101
|
+
where GLSL, WGSL and Metal refuse, so it makes every conversion explicit first;
|
|
102
|
+
the printers then differ in spelling, plus what WGSL lacks (overloading,
|
|
103
|
+
ternaries, swizzle assignment, assignable parameters). On the web the colour
|
|
104
|
+
switch stays a runtime branch on the frame's `opt.x`, since a web build does not
|
|
105
|
+
know the project's colour space when it prints.
|
|
106
|
+
|
|
107
|
+
`src/lib/lib.test.ts` regenerates everything and fails on any byte of
|
|
108
|
+
difference, the `.cginc` copies included in the container, and OneJS's
|
|
109
|
+
`SLSharedLibraryTests` checks them from the other side. What proves the
|
|
110
|
+
translations draw the same picture: the goldens compile the whole library on
|
|
111
|
+
WebGPU and WebGL2 and draw every fixture; OneJS's parity harness holds the web
|
|
112
|
+
output to the VM; `SLSharedLibraryTests` draws every corpus program in Unity
|
|
113
|
+
through `SLCommon.cginc` and through the translated shared subset and requires
|
|
114
|
+
them to agree; and the Metal check above compiles the shared subset.
|
|
115
|
+
|
|
116
|
+
## Goldens
|
|
117
|
+
|
|
118
|
+
`goldens/goldens.json` is every corpus fixture drawn as a Linear OneJS game
|
|
119
|
+
stores it: the package's WGSL and GLSL ES in OneJS's web frame, into an
|
|
120
|
+
`rgba8unorm-srgb` target (the format the element's render texture has), read
|
|
121
|
+
back raw, with no Unity, no UI Toolkit and no browser colour management. A
|
|
122
|
+
second host's own backend is checked against it; OneJS's parity harness is what
|
|
123
|
+
proves the web emitters equal the VM in the first place.
|
|
124
|
+
|
|
125
|
+
`npm run goldens` draws it on WebGPU and WebGL2 in a Chrome with its own
|
|
126
|
+
profile (set `CHROME` to choose one). The two backends must agree within 1/255
|
|
127
|
+
over every pixel, and three anchors must match arithmetic, not each other:
|
|
128
|
+
`orient.sl` (orientation, and the linear to sRGB store), `hex.sl` (a hex colour
|
|
129
|
+
stores as written) and `texture.sl` (a texture's orientation and sRGB decode).
|
|
130
|
+
The whole translated library must also compile on both backends, including
|
|
131
|
+
the functions no fixture reaches. The file describes the sampling grid, the
|
|
132
|
+
times and the texture every sampled slot gets. A host imports it as
|
|
133
|
+
`onejs-sl/goldens.json`. No CI runner here has a GPU, so `src/goldens.test.ts` checks instead
|
|
134
|
+
that the file still covers the corpus at today's hashes; a change that moves a
|
|
135
|
+
hash fails there until the goldens are drawn again.
|
|
136
|
+
|
|
48
137
|
## Runs anywhere ES2020 runs
|
|
49
138
|
|
|
50
139
|
The source reaches for no host API: no `fs`, `process`, `Buffer`,
|
|
@@ -56,7 +145,7 @@ and QuickJS (Magerie). Two checks hold it to that:
|
|
|
56
145
|
- `npm run test:quickjs` bundles `quickjs/corpus.ts` as one ES2020 IIFE, the
|
|
57
146
|
way Magerie bundles a script, runs it in QuickJS-ng and in a bare Node
|
|
58
147
|
context, and fails unless the two results agree byte for byte. The corpus
|
|
59
|
-
parses, encodes, fits and emits every program in `
|
|
148
|
+
parses, encodes, fits and emits every program in `corpus/`, every
|
|
60
149
|
shape at its full parameter count, and the error paths. `npm test` runs it
|
|
61
150
|
after vitest.
|
|
62
151
|
|
|
@@ -90,8 +179,8 @@ would rather write its programs out at build time.
|
|
|
90
179
|
|
|
91
180
|
**A third and fourth backend, for the browser.** A player cannot compile a
|
|
92
181
|
shader, but the page it runs in can. `web.ts` prints every program as WGSL and
|
|
93
|
-
as GLSL ES 3.00 (
|
|
94
|
-
|
|
182
|
+
as GLSL ES 3.00 (carrying the library functions it calls, translated from
|
|
183
|
+
`lib/*.hlsl`), and OneJS's
|
|
95
184
|
`Plugins/WebGL/OneJSSLWeb.jslib` compiles whichever one Unity's device speaks
|
|
96
185
|
and draws it into the element's target in place of the VM. A `.sl` import
|
|
97
186
|
carries both strings, printed at build time; an `encode()` result has them as
|
|
@@ -253,13 +342,13 @@ linear light. `sl.ramp` mixes its stops in sRGB, which is what reads as an even
|
|
|
253
342
|
ramp, and converts the result once through `TO_LINEAR`; `sl.color("#hex")` is
|
|
254
343
|
`parseColor` plus that conversion, and `sl.toLinear` is the conversion on its
|
|
255
344
|
own for a vec4 built from raw components. Both backends implement it gamma
|
|
256
|
-
aware (`sl_toLinear` in `
|
|
257
|
-
written. Alpha is coverage and is never converted. Same rule as `fx`.
|
|
345
|
+
aware (`sl_toLinear` in `lib/common.hlsl`), so a Gamma project gets the value
|
|
346
|
+
as written. Alpha is coverage and is never converted. Same rule as `fx`.
|
|
258
347
|
|
|
259
348
|
## Noise
|
|
260
349
|
|
|
261
350
|
`sl.noise`, `sl.simplex`, `sl.fbm(p, octaves, base)`, `sl.turbulence` and
|
|
262
|
-
`sl.ridged` are the fields `fx.noise` draws, from the same `
|
|
351
|
+
`sl.ridged` are the fields `fx.noise` draws, from the same `lib/noise2d.hlsl`, so
|
|
263
352
|
a simplex here is the simplex there. Octaves are 1 to 4. A program has no seed;
|
|
264
353
|
offset the input for a different field. `sl.simplex` used to be value noise on
|
|
265
354
|
a rotated lattice, and `sl.fbm` had its own value noise; both changed on
|