@swf2es/render 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/dist/webgl/atlas.d.ts +14 -1
- package/dist/webgl/atlas.d.ts.map +1 -1
- package/dist/webgl/atlas.js +119 -28
- package/dist/webgl/atlas.js.map +1 -1
- package/dist/webgl/batches.d.ts +68 -18
- package/dist/webgl/batches.d.ts.map +1 -1
- package/dist/webgl/batches.js +252 -63
- package/dist/webgl/batches.js.map +1 -1
- package/dist/webgl/draws.d.ts +26 -8
- package/dist/webgl/draws.d.ts.map +1 -1
- package/dist/webgl/draws.js +92 -36
- package/dist/webgl/draws.js.map +1 -1
- package/dist/webgl/programs.d.ts +10 -3
- package/dist/webgl/programs.d.ts.map +1 -1
- package/dist/webgl/programs.js +13 -5
- package/dist/webgl/programs.js.map +1 -1
- package/package.json +2 -2
- package/src/webgl/atlas.ts +149 -27
- package/src/webgl/batches.ts +316 -68
- package/src/webgl/draws.ts +104 -40
- package/src/webgl/programs.ts +13 -5
package/src/webgl/draws.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
fillVertex,
|
|
31
31
|
glyphsFragment,
|
|
32
32
|
glyphsVertex,
|
|
33
|
+
MERGED_UNIT,
|
|
33
34
|
meshFragment,
|
|
34
35
|
meshVertex,
|
|
35
36
|
OUTLINE_UNIT,
|
|
@@ -56,6 +57,15 @@ interface MultiDraw {
|
|
|
56
57
|
/** Last entry, table start, draws, units, batch start/count, then each unit's texture and sampling. */
|
|
57
58
|
const RUN_STRIDE = 6 + FILL_TEXTURES * 2;
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* The fewest fills a run copies into the merged stream (FillBatches): with
|
|
62
|
+
* WEBGL_multi_draw, whose one call already draws a run, enough for the GPU's
|
|
63
|
+
* sub-draws to cost more than the copy; without it, two, each fill
|
|
64
|
+
* otherwise a call of its own.
|
|
65
|
+
*/
|
|
66
|
+
const MERGED_LEAST_MULTI = 32;
|
|
67
|
+
const MERGED_LEAST = 2;
|
|
68
|
+
|
|
59
69
|
/** The most masks the stencil's eight bits count. */
|
|
60
70
|
const STENCIL_MOST = 255;
|
|
61
71
|
|
|
@@ -72,9 +82,10 @@ export interface Masks {
|
|
|
72
82
|
/**
|
|
73
83
|
* The draws of a scene list's entries into the target bound: fills in runs,
|
|
74
84
|
* one multi-draw of the atlas's index ranges a run where WEBGL_multi_draw
|
|
75
|
-
* is,
|
|
76
|
-
*
|
|
77
|
-
*
|
|
85
|
+
* is, else one draw of the run copied into the merged stream where its
|
|
86
|
+
* geometries are small; meshes and advanced text's glyphs each by a program
|
|
87
|
+
* of its own, and the masks' coverage into the stencil; and the view of the
|
|
88
|
+
* target drawn into, which each program is told.
|
|
78
89
|
*/
|
|
79
90
|
export class Draws {
|
|
80
91
|
private readonly gl: WebGL2RenderingContext;
|
|
@@ -103,9 +114,16 @@ export class Draws {
|
|
|
103
114
|
private blendBackLocation: WebGLUniformLocation | null = null;
|
|
104
115
|
/** WEBGL_multi_draw, which draws a run of fills alike a call (drawEntries), where there is. */
|
|
105
116
|
private multi: MultiDraw | null = null;
|
|
117
|
+
/**
|
|
118
|
+
* Whether, without WEBGL_multi_draw, runs are merged; false draws a call a
|
|
119
|
+
* fill, as a reference the merged draws are tested against (multi-draw.ts).
|
|
120
|
+
*/
|
|
121
|
+
merging = true;
|
|
106
122
|
/** Avoid the dynamically indexed uniform table used in the Intel GPU hang reproducer. */
|
|
107
123
|
private runTable: WebGLTexture | null = null;
|
|
108
124
|
private runBaseLocation: WebGLUniformLocation | null = null;
|
|
125
|
+
/** The table start the fill program was told last (uRunBase), -1 for none. */
|
|
126
|
+
private runBase = -1;
|
|
109
127
|
private runTableHeight = 0;
|
|
110
128
|
private runTableMost = 0;
|
|
111
129
|
private tableRows = new Int32Array(RUN_MOST);
|
|
@@ -198,15 +216,15 @@ export class Draws {
|
|
|
198
216
|
const gl = this.gl;
|
|
199
217
|
this.multi = gl.getExtension("WEBGL_multi_draw") as MultiDraw | null;
|
|
200
218
|
try {
|
|
201
|
-
this.program = linkProgram(gl, fillVertex(this.multi !== null), fillFragment);
|
|
219
|
+
this.program = linkProgram(gl, fillVertex(this.multi !== null, true), fillFragment);
|
|
202
220
|
} catch (e) {
|
|
203
221
|
if (!this.multi) {
|
|
204
222
|
throw e;
|
|
205
223
|
}
|
|
206
224
|
|
|
207
|
-
// An extension offered whose shader directive the compiler refuses:
|
|
225
|
+
// An extension offered whose shader directive the compiler refuses: runs merged alone.
|
|
208
226
|
this.multi = null;
|
|
209
|
-
this.program = linkProgram(gl, fillVertex(false), fillFragment);
|
|
227
|
+
this.program = linkProgram(gl, fillVertex(false, true), fillFragment);
|
|
210
228
|
}
|
|
211
229
|
|
|
212
230
|
this.unitIds.fill(-1);
|
|
@@ -223,8 +241,10 @@ export class Draws {
|
|
|
223
241
|
this.runTableMost = textureMost;
|
|
224
242
|
this.prepared = false;
|
|
225
243
|
this.runBaseLocation = gl.getUniformLocation(this.program, "uRunBase");
|
|
244
|
+
this.runBase = -1;
|
|
245
|
+
this.batches.setUp(textureMost);
|
|
246
|
+
gl.uniform1i(gl.getUniformLocation(this.program, "uMergedRows"), MERGED_UNIT);
|
|
226
247
|
if (this.multi) {
|
|
227
|
-
this.batches.setUp();
|
|
228
248
|
this.sizeRunTable(1);
|
|
229
249
|
gl.uniform1i(gl.getUniformLocation(this.program, "uRunTable"), RUN_UNIT);
|
|
230
250
|
}
|
|
@@ -268,13 +288,21 @@ export class Draws {
|
|
|
268
288
|
this.lastRow = -1;
|
|
269
289
|
}
|
|
270
290
|
|
|
271
|
-
/**
|
|
291
|
+
/**
|
|
292
|
+
* Upload before any draws, so that updating a run cannot stall earlier
|
|
293
|
+
* draws reading it: the run table, with WEBGL_multi_draw, and the merged
|
|
294
|
+
* stream and its rows.
|
|
295
|
+
*/
|
|
272
296
|
prepare(commands: Commands, scene: SceneList): void {
|
|
273
297
|
this.prepared = false;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
298
|
+
const multi = this.multi !== null;
|
|
299
|
+
// Without a multi-draw, rows are told by uniform or merged; the table is not read.
|
|
300
|
+
const tableMost = multi ? RUN_MOST * this.runTableMost : Number.POSITIVE_INFINITY;
|
|
301
|
+
const least = multi
|
|
302
|
+
? MERGED_LEAST_MULTI
|
|
303
|
+
: this.merging
|
|
304
|
+
? MERGED_LEAST
|
|
305
|
+
: Number.POSITIVE_INFINITY;
|
|
278
306
|
this.batches.reset();
|
|
279
307
|
if (commands.length > this.commandStarts.length) {
|
|
280
308
|
this.commandStarts = new Uint32Array(commands.ops.length / 4);
|
|
@@ -309,16 +337,13 @@ export class Draws {
|
|
|
309
337
|
|
|
310
338
|
i = this.gatherRun(scene, i, end, stencil);
|
|
311
339
|
const needed = count + this.runCount;
|
|
312
|
-
if (needed >
|
|
340
|
+
if (needed > tableMost) {
|
|
313
341
|
// An unusually large frame still draws by updating the first row a run at a time.
|
|
314
342
|
return;
|
|
315
343
|
}
|
|
316
344
|
|
|
317
345
|
if (needed > this.tableRows.length) {
|
|
318
|
-
const size = Math.min(
|
|
319
|
-
RUN_MOST * this.runTableMost,
|
|
320
|
-
Math.max(needed, this.tableRows.length * 2),
|
|
321
|
-
);
|
|
346
|
+
const size = Math.min(tableMost, Math.max(needed, this.tableRows.length * 2));
|
|
322
347
|
const rows = new Int32Array(size);
|
|
323
348
|
rows.set(this.tableRows);
|
|
324
349
|
this.tableRows = rows;
|
|
@@ -340,13 +365,21 @@ export class Draws {
|
|
|
340
365
|
this.runs[run + 1] = count;
|
|
341
366
|
this.runs[run + 2] = this.runCount;
|
|
342
367
|
this.runs[run + 3] = this.runUnits;
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
368
|
+
// A mask's fills merged too where each would be a call.
|
|
369
|
+
const segment =
|
|
370
|
+
!stencil || !multi
|
|
371
|
+
? this.batches.add(
|
|
372
|
+
this.runPlaces,
|
|
373
|
+
this.runRows,
|
|
374
|
+
this.runCount,
|
|
375
|
+
this.atlas.frame,
|
|
376
|
+
least,
|
|
377
|
+
!multi,
|
|
378
|
+
)
|
|
379
|
+
: null;
|
|
380
|
+
|
|
381
|
+
this.runs[run + 4] = segment ? segment.indexStart : 0;
|
|
382
|
+
this.runs[run + 5] = segment ? segment.indices : 0;
|
|
350
383
|
for (let j = 0; j < FILL_TEXTURES; j++) {
|
|
351
384
|
if (this.runUnits & (1 << j)) {
|
|
352
385
|
this.runs[run + 6 + j * 2] = this.unitIds[j];
|
|
@@ -364,7 +397,7 @@ export class Draws {
|
|
|
364
397
|
}
|
|
365
398
|
|
|
366
399
|
const height = Math.ceil(count / RUN_MOST);
|
|
367
|
-
if (height > 0) {
|
|
400
|
+
if (multi && height > 0) {
|
|
368
401
|
this.sizeRunTable(height);
|
|
369
402
|
const gl = this.gl;
|
|
370
403
|
this.state.bindTexture(RUN_UNIT, this.runTable);
|
|
@@ -641,20 +674,27 @@ export class Draws {
|
|
|
641
674
|
|
|
642
675
|
if (batchCount > 0) {
|
|
643
676
|
state.bindVertexArray(this.batches.vertexArray);
|
|
644
|
-
state.bindTexture(
|
|
645
|
-
state.bindSampler(
|
|
677
|
+
state.bindTexture(MERGED_UNIT, this.batches.rowsTexture);
|
|
678
|
+
state.bindSampler(MERGED_UNIT, null);
|
|
646
679
|
gl.drawElements(gl.TRIANGLES, batchCount, gl.UNSIGNED_INT, batchStart * 4);
|
|
647
680
|
continue;
|
|
648
681
|
}
|
|
649
682
|
|
|
650
683
|
state.bindVertexArray(this.atlas.vertexArray);
|
|
651
684
|
if (!this.multi) {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
685
|
+
// A run not merged: a call a fill, its row told as it changes.
|
|
686
|
+
const rows = this.prepared ? this.tableRows : this.runRows;
|
|
687
|
+
const counts = this.prepared ? this.tableCounts : this.runCounts;
|
|
688
|
+
const offsets = this.prepared ? this.tableOffsets : this.runOffsets;
|
|
689
|
+
for (let k = base; k < base + draws; k++) {
|
|
690
|
+
if (rows[k] !== this.lastRow) {
|
|
691
|
+
this.lastRow = rows[k];
|
|
692
|
+
gl.uniform1i(this.rowLocation, this.lastRow);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
gl.drawElements(gl.TRIANGLES, counts[k], gl.UNSIGNED_INT, offsets[k]);
|
|
655
696
|
}
|
|
656
697
|
|
|
657
|
-
gl.drawElements(gl.TRIANGLES, this.runCounts[0], gl.UNSIGNED_INT, this.runOffsets[0]);
|
|
658
698
|
continue;
|
|
659
699
|
}
|
|
660
700
|
|
|
@@ -665,7 +705,7 @@ export class Draws {
|
|
|
665
705
|
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, draws, 1, gl.RED_INTEGER, gl.INT, this.runRows);
|
|
666
706
|
}
|
|
667
707
|
|
|
668
|
-
|
|
708
|
+
this.tellRunBase(base);
|
|
669
709
|
this.multi.multiDrawElementsWEBGL(
|
|
670
710
|
gl.TRIANGLES,
|
|
671
711
|
this.prepared ? this.tableCounts : this.runCounts,
|
|
@@ -682,17 +722,34 @@ export class Draws {
|
|
|
682
722
|
}
|
|
683
723
|
}
|
|
684
724
|
|
|
725
|
+
/** The fill program told where its run starts in the run table, if it was told another. */
|
|
726
|
+
private tellRunBase(base: number): void {
|
|
727
|
+
if (base !== this.runBase) {
|
|
728
|
+
this.runBase = base;
|
|
729
|
+
this.gl.uniform1i(this.runBaseLocation, base);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
685
733
|
/**
|
|
686
734
|
* The fills from entry `i` on that one call draws, as many as fit its
|
|
687
|
-
* textures (FILL_TEXTURES, each with its sampling)
|
|
688
|
-
*
|
|
689
|
-
*
|
|
690
|
-
*
|
|
735
|
+
* textures (FILL_TEXTURES, each with its sampling), RUN_MOST at most:
|
|
736
|
+
* their runCounts, runOffsets and runRows (FILL_SLOT), and the units their
|
|
737
|
+
* textures take in runUnits. Without WEBGL_multi_draw, a run is of
|
|
738
|
+
* geometries too large to merge (Place.batch), of geometries added this
|
|
739
|
+
* frame, or of stable ones alone, so that a stable run's merged copy is
|
|
740
|
+
* drawn again while a part of it changes from frame to frame; and without
|
|
741
|
+
* merging each fill is a run. The last entry gathered, past those whose
|
|
742
|
+
* texture is gone, which draw nothing.
|
|
691
743
|
*/
|
|
692
744
|
private gatherRun(scene: SceneList, i: number, end: number, stencil: boolean): number {
|
|
693
745
|
const places = this.atlas.places;
|
|
694
746
|
const textures = this.gpu.textures;
|
|
695
|
-
const
|
|
747
|
+
const single = !this.multi;
|
|
748
|
+
const most = this.multi || this.merging ? RUN_MOST : 1;
|
|
749
|
+
const frame = this.atlas.frame;
|
|
750
|
+
// Without a multi-draw, what the run is of: geometries too large to merge, geometries added
|
|
751
|
+
// this frame, or stable ones, whose merged copy later frames draw again.
|
|
752
|
+
let kind = -1;
|
|
696
753
|
let draws = 0;
|
|
697
754
|
let last = i;
|
|
698
755
|
this.runUnits = 0;
|
|
@@ -711,6 +768,15 @@ export class Draws {
|
|
|
711
768
|
break;
|
|
712
769
|
}
|
|
713
770
|
|
|
771
|
+
if (single) {
|
|
772
|
+
const of = !place.batch ? 0 : place.batch.frame === frame ? 1 : 2;
|
|
773
|
+
if (draws === 0) {
|
|
774
|
+
kind = of;
|
|
775
|
+
} else if (of !== kind) {
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
714
780
|
const id = stencil ? -1 : scene.texture[j];
|
|
715
781
|
let slot = 0;
|
|
716
782
|
if (id >= 0) {
|
|
@@ -916,9 +982,7 @@ export class Draws {
|
|
|
916
982
|
|
|
917
983
|
/** The programs and draw table made on the context, deleted. */
|
|
918
984
|
destroy(): void {
|
|
919
|
-
|
|
920
|
-
this.batches.destroy();
|
|
921
|
-
}
|
|
985
|
+
this.batches.destroy();
|
|
922
986
|
|
|
923
987
|
if (this.runTable) {
|
|
924
988
|
this.state.dropTexture(this.runTable);
|
package/src/webgl/programs.ts
CHANGED
|
@@ -70,6 +70,10 @@ export const OUTLINE_UNIT = 7;
|
|
|
70
70
|
export const FILL_UNIT = 8;
|
|
71
71
|
/** The multi-draw row table's unit, past the fill textures. */
|
|
72
72
|
export const RUN_UNIT = FILL_UNIT + FILL_TEXTURES;
|
|
73
|
+
/** The merged fills' rows' unit (FillBatches), past the run table. */
|
|
74
|
+
export const MERGED_UNIT = RUN_UNIT + 1;
|
|
75
|
+
/** The merged fills' rows a line of their integer texture: a power of two, as for RUN_MOST. */
|
|
76
|
+
export const MERGED_LINE = 1024;
|
|
73
77
|
|
|
74
78
|
/**
|
|
75
79
|
* Places a vertex by its row's transform, on a quarter of a pixel of
|
|
@@ -78,17 +82,21 @@ export const RUN_UNIT = FILL_UNIT + FILL_TEXTURES;
|
|
|
78
82
|
* space), and passes on its straight colour, the row's colour transform
|
|
79
83
|
* and the texture it samples. uRow names the draw's row (FILL_SLOT); with
|
|
80
84
|
* `multi` (WEBGL_multi_draw), uRunTable names each draw's of a multi-draw by
|
|
81
|
-
* gl_DrawID, which is 0 in a draw of its own.
|
|
82
|
-
*
|
|
85
|
+
* gl_DrawID, which is 0 in a draw of its own. With `merged`, as with
|
|
86
|
+
* `multi`, a merged fill's vertices carry as aDraw where its packed row is
|
|
87
|
+
* in uMergedRows, which the stream keeps for its copy, so that the row
|
|
88
|
+
* changes from frame to frame where the vertices need not; the atlas leaves
|
|
89
|
+
* that attribute disabled and negative.
|
|
83
90
|
*/
|
|
84
|
-
export const fillVertex = (multi: boolean) => `#version 300 es
|
|
91
|
+
export const fillVertex = (multi: boolean, merged = multi) => `#version 300 es
|
|
85
92
|
${multi ? "#extension GL_ANGLE_multi_draw : require" : ""}
|
|
86
93
|
precision highp float;
|
|
87
94
|
layout(location = ${POSITION_AT}) in vec2 aPosition;
|
|
88
95
|
layout(location = ${TEXEL_AT}) in vec2 aTexel;
|
|
89
96
|
layout(location = ${COLOR_AT}) in vec4 aColor;
|
|
90
97
|
uniform highp sampler2D uRows;
|
|
91
|
-
${
|
|
98
|
+
${merged ? `layout(location = ${DRAW_AT}) in int aDraw;\nuniform highp isampler2D uMergedRows;` : ""}
|
|
99
|
+
${multi ? "uniform highp isampler2D uRunTable;\nuniform int uRunBase;" : "uniform int uRow;"}
|
|
92
100
|
uniform vec4 uView;
|
|
93
101
|
uniform float uUnit;
|
|
94
102
|
out vec4 vColor;
|
|
@@ -98,7 +106,7 @@ flat out vec4 vAdd;
|
|
|
98
106
|
flat out int vSlot;
|
|
99
107
|
|
|
100
108
|
void main(void) {
|
|
101
|
-
int draw = ${
|
|
109
|
+
int draw = ${merged ? `aDraw >= 0 ? texelFetch(uMergedRows, ivec2(aDraw & ${MERGED_LINE - 1}, aDraw >> ${Math.log2(MERGED_LINE)}), 0).r : ` : ""}${multi ? `texelFetch(uRunTable, ivec2((uRunBase + gl_DrawID) & ${RUN_MOST - 1}, (uRunBase + gl_DrawID) >> ${Math.log2(RUN_MOST)}), 0).r` : "uRow"};
|
|
102
110
|
int row = draw & ${(1 << FILL_SLOT) - 1};
|
|
103
111
|
vSlot = (draw >> ${FILL_SLOT}) & 15;
|
|
104
112
|
ivec2 at = ivec2((row & ${ROWS_A_LINE - 1}) * ${ROW_TEXELS}, row >> ${Math.log2(ROWS_A_LINE)});
|