@swf2es/context3d 0.1.18 → 0.1.20

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
@@ -1,7 +1,7 @@
1
- # Experimental Context3D backend
1
+ # Context3D backend
2
2
 
3
- `@swf2es/context3d` provides resource/lifecycle contracts and AGAL v1 to GLSL
4
- translation. Its core has no dependencies or browser types. The optional
3
+ `@swf2es/context3d` provides resource/lifecycle contracts and AGAL 1, 2 and 3 to
4
+ GLSL ES 3.00 translation, for every Stage3D profile. Its core has no dependencies or browser types. The optional
5
5
  `@swf2es/context3d/webgl` entry exports `WebGLContext3D`, which owns the supplied
6
6
  WebGL2 context exclusively. It does not share GL state or resources with the
7
7
  display list's renderer.
@@ -14,7 +14,7 @@ and render-state constants live beside those modules. These are internal splits;
14
14
  the package entries and ownership contracts stay the same.
15
15
 
16
16
  This package does not enable Stage3D playback. The separate
17
- `@swf2es/player/context3d` entry installs experimental Flash bindings, and
17
+ `@swf2es/player/context3d` entry installs the Flash bindings, and
18
18
  `@swf2es/player-hosts/stage3d` places canvases and attaches browser loss/restoration
19
19
  listeners. Install the bindings before loading playerglobal, and call their
20
20
  returned teardown before destroying Scripting. Default playback still reports
@@ -81,13 +81,101 @@ through is made at its first pixel upload or CPU decoding, so compressed
81
81
  textures uploaded as blocks on S3TC have none. Samplers must
82
82
  read a texture as what it is, AGAL's format DXT1 or DXT5 for a compressed one
83
83
  (#3763), where `samplerFormats` is set, as the player sets it for content from
84
- SWF 17 on. `rgbaHalfFloat` and the packed formats remain unsupported and return
85
- Error #3708 before backend allocation.
84
+ SWF 17 on, or RGBA for the packed and half-float formats.
85
+
86
+ `bgrPacked565` and `bgraPacked4444` are stored at 8 bits a channel (RGB8 and
87
+ RGBA8), as AIR draws into them: an upload keeps each channel's high bits and
88
+ widens them back as Direct3D reads them (`0x12` becomes `0x10` in 5:6:5), from a
89
+ BitmapData's premultiplied pixels or from little-endian words (5:6:5 red high,
90
+ 4:4:4:4 alpha, red, green, blue from the high nibble), two bytes a texel. 5:6:5
91
+ reads alpha 1. `rgbaHalfFloat` is RGBA16F, eight bytes a texel in R, G, B, A
92
+ order; a bitmap goes up as its bytes over 255. Drawing into one keeps values past
93
+ 1, and needs `EXT_color_buffer_float`, which every desktop WebGL 2 has. A clear's
94
+ colour is cut to 8 bits a channel on every target, as AIR clears through
95
+ Direct3D's 8-bit colour, by truncation: 0.5 clears to 127, and a half-float
96
+ target within 0 to 1.
97
+
98
+ ## Profiles
99
+
100
+ `Context3D.profile` sets what a context's programs, textures and targets may be
101
+ (`profileLimits`), as AIR 51.3 grants them under Wine, where it serves every
102
+ profile on Direct3D 9Ex (`tests/context3d`'s `Profiles.as`, `AGALProfiles.as`,
103
+ `AGALStandard.as`, `TextureFormats.as` and `MultipleTargets.as` hold the
104
+ references). Every profile has 16
105
+ sampler and vertex-stream slots, 250 vertex and 200 fragment constants for the
106
+ setters, cube faces up to 1024 and back buffers up to 16384. A constant setter
107
+ whose registers start or end past 250 or 200 is #2006 in every profile, a
108
+ matrix's four too; one within them writes them all, though an AGAL 1 program
109
+ reads only the first 128 and 28, and AGAL 2 the first 250 and 64:
110
+
111
+ | Profile | AGAL | Texture | RectangleTexture | rgbaHalfFloat | Colour outputs |
112
+ | --- | --- | --- | --- | --- | --- |
113
+ | `baselineConstrained` | 1 | 2048 | none (#3782) | no (#3759) | 1 |
114
+ | `baseline` | 1 | 2048 | 2048 | no | 1 |
115
+ | `baselineExtended` | 1 | 4096 | 4096 | no | 1 |
116
+ | `standardConstrained` | 1, 2 | 4096 | 4096 | yes | 1 |
117
+ | `standard` | 1, 2 | 4096 | 4096 | yes | 4 |
118
+ | `standardExtended` | 1, 2, 3 | 4096 | 4096 | yes | 4 |
119
+
120
+ What each AGAL version's programs may use (version 0 is 1; a version past the
121
+ profile's is #3725):
122
+
123
+ | | AGAL 1 | AGAL 2 | AGAL 3 |
124
+ | --- | --- | --- | --- |
125
+ | Tokens a program | 200 | 1024 | 2048 |
126
+ | `va` | 8 | 8 | 16 |
127
+ | `vc` / `fc` | 128 / 28 | 250 / 64 | 250 / 200 |
128
+ | `vt`, `ft` | 8 (7 in `baselineConstrained`) | 26 | 26 |
129
+ | `v` | 8 | 10 (8 in `standardConstrained`) | 10 |
130
+ | `fs` | 8 | 16 (8 in `standardConstrained`) | 16 |
131
+ | `oc` | 1 | 4 (1 in `standardConstrained`) | 4 |
132
+ | `od` | — | `od.x` (none in `standardConstrained`) | `od.x` |
133
+
134
+ AGAL 2 adds `ddx` and `ddy` (fragment programs, not in conditionals; `ddy` grows
135
+ down the target, as AIR's), and the conditionals `ife`, `ine`, `ifg` and `ifl`
136
+ (scalar operands, compared as `==`, `!=`, `>` and `<`), `els` and `eif`, at most
137
+ four deep. Both branches run for every pixel and only their writes are
138
+ predicated, as Direct3D's predication runs them, so derivatives stay defined:
139
+ nothing branches in GLSL. AIR's rules hold: no output written in a conditional
140
+ (#3751), no empty branch (#3748), a texture read in one takes a varying alone
141
+ (#3741), and after `eif` a temporary counts as written where the `els` branch
142
+ wrote it, or, with no `els`, where it was before the `if`. `od` writes the
143
+ depth, clamped by the depth buffer. AIR's indirect reads reach the first 128
144
+ vertex constants in every version and read 0 past them, so a program's bank
145
+ stays `vc[128]`, indexed as AGAL 1's is; constants past it are uniforms of their
146
+ own. Fragment programs have no indirect reads (#3639). AIR reads `iid` from
147
+ vertex stream 15. In every version `sne` compares, two constant operands are
148
+ refused (#3625, as are `kil`, `ddx` and `ddy` of a constant), each colour output
149
+ is written once (#3744) from `oc0` up without gaps (#3775), and samplers take
150
+ the four wraps and any format, which a draw then checks.
151
+
152
+ Colour outputs 1 to 3 (`setColorOutput`) draw beside the target: the player
153
+ binds them for `setRenderToTexture`'s `colorOutputIndex`, refuses them beside the
154
+ back buffer (#3728) or unlike the target in size, format, depth or antialiasing
155
+ (#3729), and a draw whose program writes another number of outputs (#3774).
156
+ `setRenderToBackBuffer` and `present` unbind them. The backend attaches them to
157
+ the target's framebuffer only while they are bound, so a target drawn alone
158
+ pays nothing.
159
+
160
+ Left out, and why:
161
+
162
+ - `drawTrianglesInstanced` and `createVertexBufferForInstances`, which AIR has
163
+ and Flash Player 32's playerglobal does not; `iid` reads stream 15 meanwhile.
164
+ - Colour outputs on an antialiased target (#3708): AIR takes them.
165
+ - The same texture bound to two outputs, which AIR draws into with the later one.
166
+ - `baselineConstrained` fragment programs are held to 96 instructions (#3715),
167
+ ps_2_0's 64 arithmetic and 32 texture ones, counted as AGAL's: AIR counts
168
+ Direct3D's, of which a matrix, `nrm` or a comparison takes several.
169
+ - A RectangleTexture as large as the back buffer where that is larger than the
170
+ profile's size, which AIR's message names but no test has checked.
171
+ - Conditionals in vertex programs: AIR's validation takes them, then under Wine
172
+ its Direct3D 9 compile fails (#3613), so no reference shows what they draw;
173
+ swf2es runs them as it runs a fragment program's.
86
174
 
87
175
  Core failures carry typed reasons. The Flash adapter maps them to catchable AS3
88
176
  errors, including resource limits (#3691), disposed objects (#3694), draw bounds
89
- and AGAL validation/linkage. Known unavailable modes or profiles report an
90
- asynchronous ErrorEvent #3702 so content can retry baseline. Concurrent requests
177
+ and AGAL validation/linkage. Every profile is served; the software render mode
178
+ reports an asynchronous ErrorEvent #3702 so content can retry. Concurrent requests
91
179
  coalesce; requesting again after creation retires the preceding context and
92
180
  creates a new one. Broader unchecked-error precedence remains experimental.
93
181
  The constructor rejects antialiased host contexts before allocating GPU handles:
@@ -129,10 +217,11 @@ not prompt or guaranteed; explicit disposal remains preferable, and the hard
129
217
  resource budgets still apply. Direct backend callers own their resources and
130
218
  must dispose them or the context.
131
219
 
132
- The current API and validation are experimental. Supported operations, AIR
220
+ Supported operations, AIR
133
221
  references, unsupported formats/profiles and lifecycle stress tests are tracked
134
- in [tests/context3d](../../tests/context3d/README.md). Stage3D playback remains off
135
- by default. A web host can explicitly opt in before loading its first player:
222
+ in [tests/context3d](../../tests/context3d/README.md). Stage3D playback is off by
223
+ default in the web element, and on in the desktop app, whose View menu turns it
224
+ off. A web host can explicitly opt in before loading its first player:
136
225
 
137
226
  ```ts
138
227
  import { configure } from "@swf2es/web";
@@ -163,8 +252,11 @@ configure({
163
252
  });
164
253
  ```
165
254
 
166
- Each requested slot needs a fresh surface. `configure({ stage3D: null })` disables
167
- the experiment for subsequent loads. The web element owns native installation,
255
+ Each requested slot needs a fresh surface. In place of the factory, `stage3D` takes
256
+ a loader, `{ load: () => import("./my-stage3d.js").then((m) => m.create) }`, which
257
+ the element calls at a SWF's first `requestContext3D`: a SWF that never asks loads
258
+ no backend, and one whose load fails gets #3702. `configure({ stage3D: null })` disables
259
+ Stage3D for subsequent loads. The web element owns native installation,
168
260
  composition, cancellation, restoration and teardown for each load. GPU backend
169
261
  selection stays with the host; the default web entry does not eagerly import
170
262
  the optional bindings or a backend. No new dependencies are required by `web`.
@@ -176,28 +268,26 @@ they are host policy, not AIR limits or a guarantee against context loss. Tune
176
268
  them for the workload and account for concurrent slots and players. The limits
177
269
  exclude driver overhead and back-buffer attachments, so the browser can still
178
270
  lose a context before a logical allocation limit is reached. The public demo
179
- keeps Stage3D off by default; its experimental checkbox opts in with these lower budgets.
271
+ keeps Stage3D off by default; its checkbox opts in with these lower budgets.
180
272
 
181
273
  Stage3D positions follow the embedding's `scale`/`salign` placement. Configured
182
274
  buffer sizes remain in pixels; resizing or changing device pixel ratio never
183
275
  implicitly reallocates them. The host clips the viewports, makes the display
184
276
  list transparent while contexts exist, and keeps overlapping players' canvases
185
277
  in separate stacks. The web host honors ActionScript changes to
186
- `Stage.scaleMode` and `Stage.align`, with Stage3D opted in or not; only the
187
- opt-in gives the top and left edges precedence when an alignment names both
278
+ `Stage.scaleMode` and `Stage.align`, with Stage3D configured or not; only with it configured do the top and left edges take precedence when an alignment names both
188
279
  opposite edges. In `noScale`, Stage dimensions follow the
189
280
  embedding's CSS size and resize events are synchronous after placement updates;
190
281
  other modes report the authored dimensions. Display-list pixels and input use
191
282
  the same viewport, including coordinates outside the authored rectangle.
192
283
  A DPR change affects display-list resolution without changing Stage dimensions
193
284
  or reallocating Stage3D buffers. Script settings override embedding defaults
194
- independently. The desktop app offers the same host through View › Stage3D
195
- (Experimental), off by default, with a remembered choice that restarts the
196
- movie when changed. It uses the backend's per-type resource count limits and
285
+ independently. The desktop app uses the same host, on by default; View › Stage3D turns it
286
+ off and on, with a remembered choice that restarts the movie when changed. It uses the backend's per-type resource count limits and
197
287
  byte budgets. The public demo lazily loads the backend when Stage3D is selected
198
288
  and restarts the current SWF when the option changes. Its Restart and Close
199
- controls release the preceding contexts. Best-resolution buffers remain later
200
- work. None of this changes the ActionScript Worker API.
289
+ controls release the preceding contexts. `wantsBestResolution` back buffers are drawn at the screen's pixels
290
+ (see tests/context3d). None of this changes the ActionScript Worker API.
201
291
 
202
292
  A future WebGPU backend can reuse the Flash adapter, resource contracts and AIR
203
293
  fixtures. It still needs AGAL-to-WGSL translation, GPU resource/binding handling,
@@ -209,7 +299,7 @@ Flash execution would need validation before full compatibility could be claimed
209
299
 
210
300
  The display list and Stage3D use separate canvases. Display-list blend effects
211
301
  sample the transparent 2D back buffer rather than Stage3D color, so blending
212
- across those layers is an experimental limitation. `Playback.destroy()` disposes
302
+ across those layers is a known limitation. `Playback.destroy()` disposes
213
303
  the display-list scene before the renderer on ordinary loads as well as Stage3D
214
304
  loads; this intentional shared cleanup releases cached text-style listeners.
215
305
 
package/dist/agal.d.ts CHANGED
@@ -1,10 +1,12 @@
1
+ import { type Profile } from "./backend.js";
1
2
  export type ProgramType = "vertex" | "fragment";
2
3
  export interface SamplerSource {
3
4
  index: number;
4
5
  /** What the sampler reads: 0 RGBA, 1 DXT1 ("compressed"), 2 DXT5 ("compressedAlpha"). */
5
6
  format: number;
6
7
  filter: number;
7
- repeat: boolean;
8
+ /** AGAL's wrap: 0 clamp, 1 repeat, 2 clamp_u_repeat_v, 3 repeat_u_clamp_v. */
9
+ wrap: number;
8
10
  mip: number;
9
11
  cube: boolean;
10
12
  ignore: boolean;
@@ -18,6 +20,13 @@ export interface ShaderSource {
18
20
  constants: number[];
19
21
  indirect: boolean;
20
22
  samplers: SamplerSource[];
23
+ /** Colour outputs a fragment program writes, oc0 up: 1 to 4. */
24
+ outputs: number;
21
25
  }
22
- export declare function translate(bytes: Uint8Array, stage: ProgramType): ShaderSource;
26
+ /**
27
+ * The vertex constants an indirect read reaches: AIR's reach the first 128 in AGAL 2 and 3
28
+ * too, and read 0 past them; the rest only direct reads reach.
29
+ */
30
+ export declare const INDIRECT_BANK = 128;
31
+ export declare function translate(bytes: Uint8Array, stage: ProgramType, profile?: Profile): ShaderSource;
23
32
  //# sourceMappingURL=agal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agal.d.ts","sourceRoot":"","sources":["../src/agal.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAQD,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,YAAY,CA4c7E"}
1
+ {"version":3,"file":"agal.d.ts","sourceRoot":"","sources":["../src/agal.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAmC,MAAM,cAAc,CAAC;AAG7E,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAsDD;;;GAGG;AACH,eAAO,MAAM,aAAa,MAAM,CAAC;AAiBjC,wBAAgB,SAAS,CACvB,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,OAAoB,GAC5B,YAAY,CAqsBd"}