@expofp/renderer 3.38.0 → 3.39.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/dist/controls/camera-api.d.ts +28 -0
- package/dist/controls/camera-api.js +33 -10
- package/dist/controls/hooks.js +2 -0
- package/dist/core/InstanceUniforms.d.ts +15 -0
- package/dist/core/InstanceUniforms.js +32 -0
- package/dist/core/batch/BatchedMesh.js +6 -0
- package/dist/core/instanced/instanced-material.js +5 -1
- package/dist/core/lines/BatchedLines.d.ts +9 -7
- package/dist/core/lines/BatchedLines.js +9 -7
- package/dist/core/lines/{FrustumCulling.d.ts → FrustumCullingLines.d.ts} +7 -6
- package/dist/core/lines/{FrustumCulling.js → FrustumCullingLines.js} +2 -2
- package/dist/core/lines/{Raycasting.d.ts → RaycastingLines.d.ts} +7 -6
- package/dist/core/lines/{Raycasting.js → RaycastingLines.js} +2 -2
- package/dist/core/lines/lines-material.js +10 -1
- package/dist/core/sprites/BatchedSprites.d.ts +115 -0
- package/dist/core/sprites/BatchedSprites.js +205 -0
- package/dist/core/sprites/RaycastingSprites.d.ts +41 -0
- package/dist/core/sprites/RaycastingSprites.js +71 -0
- package/dist/core/sprites/sprite-material.d.ts +59 -0
- package/dist/core/sprites/sprite-material.js +192 -0
- package/dist/core/text/BatchedText.d.ts +6 -0
- package/dist/core/text/BatchedText.js +6 -0
- package/dist/core/text/MemberTexture.js +55 -1
- package/dist/core/text/Text.d.ts +16 -1
- package/dist/core/text/Text.js +15 -0
- package/dist/core/text/batched-text-material.js +4 -2
- package/dist/events/LayoutDriver.d.ts +6 -6
- package/dist/events/LayoutDriver.js +9 -12
- package/dist/events/layout-targets.d.ts +35 -34
- package/dist/events/layout-targets.js +127 -107
- package/dist/objects/containers/hooks.d.ts +19 -4
- package/dist/objects/containers/hooks.js +101 -23
- package/dist/objects/containers/mesh-writes.js +3 -3
- package/dist/objects/images/ImageInstance.js +104 -36
- package/dist/objects/images/Images.d.ts +8 -7
- package/dist/objects/images/Images.js +94 -28
- package/dist/objects/images/image-container.d.ts +14 -3
- package/dist/objects/images/image-container.js +19 -5
- package/dist/objects/layer/Layer.d.ts +7 -6
- package/dist/objects/layer/Layer.js +77 -57
- package/dist/objects/layer/layer-context.d.ts +74 -0
- package/dist/objects/layer/layer-context.js +82 -0
- package/dist/objects/materials/ColorMaterial.js +16 -3
- package/dist/objects/materials/LineMaterial.js +4 -2
- package/dist/objects/materials/TextureMaterial.js +4 -2
- package/dist/objects/materials/effects/color-dim.d.ts +3 -11
- package/dist/objects/materials/effects/color-dim.js +17 -17
- package/dist/objects/materials/effects/effects-context.d.ts +6 -5
- package/dist/objects/materials/shared.d.ts +18 -0
- package/dist/objects/materials/shared.js +21 -0
- package/dist/objects/models/Models.js +1 -8
- package/dist/objects/shapes/ShapeInstance.js +1 -2
- package/dist/objects/shapes/Shapes.js +2 -9
- package/dist/objects/text/TextInstance.js +2 -2
- package/dist/objects/text/text-layout.d.ts +13 -4
- package/dist/objects/text/text-layout.js +30 -4
- package/dist/space/Space.d.ts +15 -0
- package/dist/space/Space.js +16 -10
- package/dist/types/defs.d.ts +37 -0
- package/dist/utils/logging.d.ts +6 -3
- package/dist/utils/logging.js +15 -7
- package/dist/utils/math.d.ts +11 -0
- package/dist/utils/math.js +14 -0
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Color, DataTexture, FloatType, Frustum, Matrix4, RGBAFormat, Sphere, } from 'three';
|
|
1
|
+
import { Color, DataTexture, FloatType, Frustum, Matrix4, RGBAFormat, Sphere, Vector3, } from 'three';
|
|
2
|
+
import { Y_DOWN_FLIP } from '../../space/Space';
|
|
2
3
|
/**
|
|
3
4
|
* The data texture a batch's shader reads each member's transform and style from: one 32-float row
|
|
4
5
|
* per member, refilled once per draw with frustum culling folded in.
|
|
@@ -43,6 +44,16 @@ export class MemberTexture {
|
|
|
43
44
|
.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
|
|
44
45
|
.multiply(host.matrixWorld);
|
|
45
46
|
_frustum.setFromProjectionMatrix(_matrix, camera.coordinateSystem);
|
|
47
|
+
// The camera's rotation, brought into the batch's own space, because that is where member
|
|
48
|
+
// matrices live. Computed once per draw, not once per member. `Y_DOWN_FLIP` plays the camera's
|
|
49
|
+
// own rest pose here, so `faceCamera` does not bake that pose in twice: once here and once more
|
|
50
|
+
// in the ordinary view transform at draw time. See `Y_DOWN_FLIP` in `space/Space.ts` for why
|
|
51
|
+
// this role holds regardless of a member's own scale or rotation.
|
|
52
|
+
_basis
|
|
53
|
+
.extractRotation(host.matrixWorld)
|
|
54
|
+
.transpose()
|
|
55
|
+
.multiply(_cameraBasis.extractRotation(camera.matrixWorld))
|
|
56
|
+
.multiply(Y_DOWN_FLIP);
|
|
46
57
|
// Hoisted out of the loop: `Text`'s `material` getter calls `hasOutline()`, which walks every
|
|
47
58
|
// member, so reading it per member made this loop quadratic — and it returns an *array* once
|
|
48
59
|
// outlines are on, whose `.color` is undefined. The material being drawn is already in hand.
|
|
@@ -52,6 +63,7 @@ export class MemberTexture {
|
|
|
52
63
|
// An unsynced member has no layout to write and draws nothing either.
|
|
53
64
|
if (!text?.textRenderInfo)
|
|
54
65
|
continue;
|
|
66
|
+
faceCamera(text, _basis);
|
|
55
67
|
const start = memberId * FLOATS_PER_MEMBER;
|
|
56
68
|
if (isDrawn(text)) {
|
|
57
69
|
this.writeMember(texData, start, text, material, batchColor);
|
|
@@ -160,6 +172,43 @@ export class MemberTexture {
|
|
|
160
172
|
}
|
|
161
173
|
}
|
|
162
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Turns a screen-space member to face the camera, and leaves a flat one alone.
|
|
177
|
+
*
|
|
178
|
+
* Composed on the CPU, on a loop that already runs once per member per draw, rather than in the
|
|
179
|
+
* shader. The shader path costs twelve bytes per member of GPU memory and needs a seam on both
|
|
180
|
+
* `BatchedTextImpl.raycast` and `isDrawn`. This path costs neither, because both of those read the
|
|
181
|
+
* member's matrix already. Write the sprite matrix there and both follow.
|
|
182
|
+
*
|
|
183
|
+
* The composition is `T(anchor) . basis . T(position - anchor) . Rz(rotation.z) . S(scale)`. The
|
|
184
|
+
* basis is the camera's rotation brought into the batch's own space, corrected by `Y_DOWN_FLIP`
|
|
185
|
+
* for the camera's own rest pose (see {@link Y_DOWN_FLIP} in `space/Space.ts`). Everything else is
|
|
186
|
+
* read off the member exactly as
|
|
187
|
+
* `updateMatrix` reads it. Straight overhead the basis is the identity and this reduces to the flat
|
|
188
|
+
* matrix, which is the equality the top-down baseline asserts on screen.
|
|
189
|
+
*
|
|
190
|
+
* Written through `setMatrix` only when it changed, so a still camera costs sixteen comparisons and
|
|
191
|
+
* no bounds invalidation. A pan or a zoom costs the same, because neither moves the camera's
|
|
192
|
+
* rotation. Only a roll or a pitch dirties a row.
|
|
193
|
+
* @param text - The member to turn.
|
|
194
|
+
* @param basis - The camera basis for this draw, in the batch's own space.
|
|
195
|
+
*/
|
|
196
|
+
function faceCamera(text, basis) {
|
|
197
|
+
const anchor = text.spriteAnchor;
|
|
198
|
+
if (!anchor)
|
|
199
|
+
return;
|
|
200
|
+
// `spriteAnchor` carries no z. The offset's z is zero by construction, and the pivot's z is read
|
|
201
|
+
// off the member's own position instead.
|
|
202
|
+
_offset.set(text.position.x - anchor.x, text.position.y - anchor.y, 0);
|
|
203
|
+
_spriteMatrix
|
|
204
|
+
.copy(basis)
|
|
205
|
+
.multiply(_step.makeTranslation(_offset.x, _offset.y, _offset.z))
|
|
206
|
+
.multiply(_step.makeRotationZ(text.rotation.z))
|
|
207
|
+
.scale(text.scale)
|
|
208
|
+
.premultiply(_step.makeTranslation(anchor.x, anchor.y, text.position.z));
|
|
209
|
+
if (!text.matrix.equals(_spriteMatrix))
|
|
210
|
+
text.setMatrix(_spriteMatrix);
|
|
211
|
+
}
|
|
163
212
|
/**
|
|
164
213
|
* Whether a member draws this frame: shown, and inside the frustum this pass was set up with.
|
|
165
214
|
* @param text - The member to test.
|
|
@@ -192,3 +241,8 @@ const _color = new Color();
|
|
|
192
241
|
const _matrix = new Matrix4();
|
|
193
242
|
const _frustum = new Frustum();
|
|
194
243
|
const _sphere = new Sphere();
|
|
244
|
+
const _basis = new Matrix4();
|
|
245
|
+
const _cameraBasis = new Matrix4();
|
|
246
|
+
const _spriteMatrix = new Matrix4();
|
|
247
|
+
const _step = new Matrix4();
|
|
248
|
+
const _offset = new Vector3();
|
package/dist/core/text/Text.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matrix4 } from 'three';
|
|
1
|
+
import { Matrix4, type Vector2 } from 'three';
|
|
2
2
|
import { Text as TroikaText, type TextMaterial } from 'troika-three-text';
|
|
3
3
|
import { type BatchedTextImpl } from './BatchedText';
|
|
4
4
|
/**
|
|
@@ -45,6 +45,21 @@ export declare class TextImpl extends TroikaText {
|
|
|
45
45
|
* this initializer runs, so seeding `false` here would quietly undo them.
|
|
46
46
|
*/
|
|
47
47
|
_syncFlag: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Where this member pivots when it faces the camera, in the plan's x and y. `null` draws it flat
|
|
50
|
+
* on the plan.
|
|
51
|
+
*
|
|
52
|
+
* One object, set and cleared together, so the two halves cannot disagree. Deliberately not named
|
|
53
|
+
* `anchorX` or `anchorY`, which troika owns and lists in its syncable properties. Assigning those
|
|
54
|
+
* would re-run layout and repack the batch on every write. `position`, `quaternion`, `scale` and
|
|
55
|
+
* `matrix` are all absent from that list, which is what makes the per-draw compose free of layout.
|
|
56
|
+
*
|
|
57
|
+
* Two dimensional on purpose. Every line of a def sits at the def's own elevation, so the anchor's
|
|
58
|
+
* z always equals the member's own `position.z`. There is no separate z to store.
|
|
59
|
+
*
|
|
60
|
+
* Derived, never authored. `applyPlacement` sets it from the def's bounds.
|
|
61
|
+
*/
|
|
62
|
+
spriteAnchor: Vector2 | null;
|
|
48
63
|
/**
|
|
49
64
|
* Writes the local transform directly and tells the batch its bounds moved.
|
|
50
65
|
*
|
package/dist/core/text/Text.js
CHANGED
|
@@ -45,6 +45,21 @@ export class TextImpl extends TroikaText {
|
|
|
45
45
|
* this initializer runs, so seeding `false` here would quietly undo them.
|
|
46
46
|
*/
|
|
47
47
|
_syncFlag = true;
|
|
48
|
+
/**
|
|
49
|
+
* Where this member pivots when it faces the camera, in the plan's x and y. `null` draws it flat
|
|
50
|
+
* on the plan.
|
|
51
|
+
*
|
|
52
|
+
* One object, set and cleared together, so the two halves cannot disagree. Deliberately not named
|
|
53
|
+
* `anchorX` or `anchorY`, which troika owns and lists in its syncable properties. Assigning those
|
|
54
|
+
* would re-run layout and repack the batch on every write. `position`, `quaternion`, `scale` and
|
|
55
|
+
* `matrix` are all absent from that list, which is what makes the per-draw compose free of layout.
|
|
56
|
+
*
|
|
57
|
+
* Two dimensional on purpose. Every line of a def sits at the def's own elevation, so the anchor's
|
|
58
|
+
* z always equals the member's own `position.z`. There is no separate z to store.
|
|
59
|
+
*
|
|
60
|
+
* Derived, never authored. `applyPlacement` sets it from the def's bounds.
|
|
61
|
+
*/
|
|
62
|
+
spriteAnchor = null;
|
|
48
63
|
/**
|
|
49
64
|
* Writes the local transform directly and tells the batch its bounds moved.
|
|
50
65
|
*
|
|
@@ -56,9 +56,11 @@ export function configureDerivedMaterial(derived, base, uniforms) {
|
|
|
56
56
|
// term.) Building it here, with a lower id, restores the intended order; troika's getter finds it
|
|
57
57
|
// already cached and uses it.
|
|
58
58
|
derived._outlineMtl = makeOutlineMaterial(derived);
|
|
59
|
-
// Recompile when the uniform schema changes, since that changes the generated GLSL.
|
|
59
|
+
// Recompile when the uniform schema changes, since that changes the generated GLSL. The whole
|
|
60
|
+
// schema, not just whether a texture exists: two batches declaring different uniforms compile
|
|
61
|
+
// different source, and three compares nothing but this key.
|
|
60
62
|
const cacheKeyBase = derived.customProgramCacheKey.bind(derived);
|
|
61
|
-
derived.customProgramCacheKey = () => `efpText_${
|
|
63
|
+
derived.customProgramCacheKey = () => `efpText_${uniforms.shaderKey}|${cacheKeyBase()}`;
|
|
62
64
|
// Assignment, *not* the read-bind-wrap pattern the sibling meshes use: troika defines
|
|
63
65
|
// `onBeforeCompile` as an accessor pair whose getter returns troika's own handler and whose setter
|
|
64
66
|
// stashes ours (troika-three-utils DerivedMaterial), so calling through the getter from inside our
|
|
@@ -14,12 +14,12 @@ export interface LayoutDriverProps {
|
|
|
14
14
|
* for: under the on-demand loop the camera's own movement is what requests them, so a still plan
|
|
15
15
|
* costs nothing at all.
|
|
16
16
|
*
|
|
17
|
-
* A move
|
|
18
|
-
* at most {@link LAYOUT_BUDGET_MS},
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* stay inside the frame callback, before three's own
|
|
22
|
-
* the very frame that draws them.
|
|
17
|
+
* A move runs every stale rule at once — the cheap half — and starts a **sweep** of the writes: each
|
|
18
|
+
* frame drains the registry's write queue for at most {@link LAYOUT_BUDGET_MS}, visibility flips
|
|
19
|
+
* first and then defs inside the camera's frustum, and asks for another frame while any remain — so
|
|
20
|
+
* a plan of ten thousand labels re-writes over a handful of frames instead of stalling one, and what
|
|
21
|
+
* the user sees change lands first. The writes stay inside the frame callback, before three's own
|
|
22
|
+
* render, so they upload in the very frame that draws them.
|
|
23
23
|
*
|
|
24
24
|
* No React is involved in a re-layout. The handlers mutate def fields and the defs' own sync closures
|
|
25
25
|
* write them, so a zoom does not re-render a single component — which is what makes it affordable for
|
|
@@ -5,14 +5,12 @@ import { Frustum } from 'three';
|
|
|
5
5
|
import { useCameraControls } from '../controls';
|
|
6
6
|
import { measurePixelSize, measureRoll, pixelSizeMoved } from '../space/layout-measure';
|
|
7
7
|
import { useSpace } from '../space/Space';
|
|
8
|
-
import { createLogger } from '../utils/logging';
|
|
9
8
|
import { planFrustum } from './def-culling';
|
|
10
9
|
import { createLayoutTargets, LayoutTargetsContext } from './layout-targets';
|
|
11
|
-
const logger = createLogger('layout');
|
|
12
10
|
/**
|
|
13
|
-
* How much of a frame one drain may spend
|
|
14
|
-
* the legacy renderer's `UpdatesSystem` drained its update queue with. Small enough
|
|
15
|
-
* 60fps frame its render; the backlog it leaves is carried into the next frame
|
|
11
|
+
* How much of a frame one drain may spend writing laid-out defs into their slots, in milliseconds —
|
|
12
|
+
* the same budget the legacy renderer's `UpdatesSystem` drained its update queue with. Small enough
|
|
13
|
+
* to leave a 60fps frame its render; the backlog it leaves is carried into the next frame.
|
|
16
14
|
*/
|
|
17
15
|
const LAYOUT_BUDGET_MS = 3;
|
|
18
16
|
/**
|
|
@@ -25,12 +23,12 @@ const LAYOUT_BUDGET_MS = 3;
|
|
|
25
23
|
* for: under the on-demand loop the camera's own movement is what requests them, so a still plan
|
|
26
24
|
* costs nothing at all.
|
|
27
25
|
*
|
|
28
|
-
* A move
|
|
29
|
-
* at most {@link LAYOUT_BUDGET_MS},
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* stay inside the frame callback, before three's own
|
|
33
|
-
* the very frame that draws them.
|
|
26
|
+
* A move runs every stale rule at once — the cheap half — and starts a **sweep** of the writes: each
|
|
27
|
+
* frame drains the registry's write queue for at most {@link LAYOUT_BUDGET_MS}, visibility flips
|
|
28
|
+
* first and then defs inside the camera's frustum, and asks for another frame while any remain — so
|
|
29
|
+
* a plan of ten thousand labels re-writes over a handful of frames instead of stalling one, and what
|
|
30
|
+
* the user sees change lands first. The writes stay inside the frame callback, before three's own
|
|
31
|
+
* render, so they upload in the very frame that draws them.
|
|
34
32
|
*
|
|
35
33
|
* No React is involved in a re-layout. The handlers mutate def fields and the defs' own sync closures
|
|
36
34
|
* write them, so a zoom does not re-render a single component — which is what makes it affordable for
|
|
@@ -62,7 +60,6 @@ export function LayoutDriver(props) {
|
|
|
62
60
|
// The epsilon compares against the sweep's target size, so a camera that stopped mid-sweep does
|
|
63
61
|
// not re-mark the same sweep on every one of the frames that finish it.
|
|
64
62
|
if (pixelSize !== undefined && pixelSizeMoved(pixelSize, targets.pixelSize)) {
|
|
65
|
-
logger.debug(`pxToSvgScale ${+pixelSize.toFixed(3)}`);
|
|
66
63
|
targets.applyScale(pixelSize);
|
|
67
64
|
}
|
|
68
65
|
// Roll has no epsilon — the imperative renderer swept its roll handlers on any bearing change
|
|
@@ -5,67 +5,68 @@ import { type LayerDef, type RenderableDef } from '../types/defs';
|
|
|
5
5
|
* layout axes.
|
|
6
6
|
*
|
|
7
7
|
* Every def here declares its own `onScale` or `onRoll` — the registry never holds a handler, only
|
|
8
|
-
* the value each def's rule last ran at, per axis. One registry per renderer, reached through
|
|
9
|
-
* so two renderers showing the same defs at different zooms do not lay
|
|
8
|
+
* the value each def's rule last ran at, per axis. One registry per renderer, reached through
|
|
9
|
+
* {@link LayoutTargetsContext}, so two renderers showing the same defs at different zooms do not lay
|
|
10
|
+
* each other's out.
|
|
10
11
|
*
|
|
11
|
-
* A
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* A move splits in two. **The rules all run at once**, in the frame that noticed it: they are the
|
|
13
|
+
* cheap half — arithmetic over a def's own fields — and running them together is what lets every
|
|
14
|
+
* def's *decision*, a dot's "show me now" included, exist the moment the camera moves. **The writes
|
|
15
|
+
* are a sweep**: what the rules reported changed is queued and {@link drain} carries it to the GPU a
|
|
16
|
+
* frame's budget at a time — defs whose visibility flipped first, then the rest the camera can see,
|
|
17
|
+
* then the culled. The queue's shape is the legacy renderer's `UpdatesSystem` (fp-engine
|
|
18
|
+
* `core/updates.ts`); its unit is a def whose fields moved.
|
|
16
19
|
*/
|
|
17
20
|
export interface LayoutTargets {
|
|
18
21
|
/**
|
|
19
|
-
* The pixel size the registered defs are laid out at
|
|
20
|
-
*
|
|
21
|
-
* against so a camera that stopped moving does not re-mark the same sweep every frame.
|
|
22
|
+
* The pixel size the registered defs are laid out at, which is what the driver's epsilon compares
|
|
23
|
+
* against.
|
|
22
24
|
*/
|
|
23
25
|
readonly pixelSize: number;
|
|
24
26
|
/**
|
|
25
27
|
* The roll the registered defs are laid out at, in radians clockwise from north — the second
|
|
26
|
-
* layout axis, compared the way {@link pixelSize} is
|
|
27
|
-
* drained value.
|
|
28
|
+
* layout axis, compared the way {@link pixelSize} is.
|
|
28
29
|
*/
|
|
29
30
|
readonly roll: number;
|
|
30
|
-
/** Whether
|
|
31
|
+
/** Whether writes are still queued — what makes a caller keep frames coming. */
|
|
31
32
|
readonly hasWork: boolean;
|
|
32
33
|
/**
|
|
33
|
-
* Registers defs for re-layout, and lays out the ones that are not current — so a def
|
|
34
|
-
* from the moment it is registered, and a membership change re-lays out only what it
|
|
34
|
+
* Registers defs for re-layout, and lays out and writes the ones that are not current — so a def
|
|
35
|
+
* is current from the moment it is registered, and a membership change re-lays out only what it
|
|
36
|
+
* added.
|
|
35
37
|
* @param defs - The defs to lay out; every one of them declares an `onScale` or an `onRoll`.
|
|
36
38
|
* @returns An unregister function; it also drops whatever of these defs a sweep still queued.
|
|
37
39
|
*/
|
|
38
40
|
register(defs: readonly RenderableDef[]): () => void;
|
|
39
41
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
42
|
+
* Records the new pixel size and runs every registered scale rule against it, queueing what they
|
|
43
|
+
* report changed. Nothing is written here — that is {@link drain}'s job. Applying again before
|
|
44
|
+
* the queue drains re-runs the rules at the newer size, and a queued def is written once, with
|
|
45
|
+
* whatever its fields hold by then: the writes coalesce by construction.
|
|
44
46
|
* @param pixelSize - The new pixel size.
|
|
45
47
|
*/
|
|
46
48
|
applyScale(pixelSize: number): void;
|
|
47
49
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
+
* {@link applyScale}'s counterpart on the other axis, running only the rules that declare an
|
|
51
|
+
* `onRoll`. Both axes feed the one write queue.
|
|
50
52
|
* @param roll - The new roll, in radians clockwise from north.
|
|
51
53
|
*/
|
|
52
54
|
applyRoll(roll: number): void;
|
|
53
55
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
+
* Writes queued defs within a frame's budget, and says whether any remain — the caller's cue to
|
|
57
|
+
* ask for another frame.
|
|
56
58
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* Three passes, in priority order: defs whose rule flipped them between hidden and shown, then
|
|
60
|
+
* every other queued def, then the ones an earlier pass deferred because the frustum rejects
|
|
61
|
+
* them. A flip matters most because it is what the user sees change — a label vanishing or a dot
|
|
62
|
+
* appearing — while a resize of something already shown can wait a frame.
|
|
61
63
|
*
|
|
62
|
-
* **A drain always takes at least one def**,
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* hidden defs are deferred.
|
|
64
|
+
* **A drain always takes at least one def**, however little budget is left — including none,
|
|
65
|
+
* which is what a worker descheduled before the first check leaves. That is what makes a sweep
|
|
66
|
+
* unable to stall: each drain shortens the queue, so the frames the driver keeps asking for
|
|
67
|
+
* eventually end it.
|
|
68
|
+
* @param frustum - The camera's frustum in plan space, when the caller has one; without it
|
|
69
|
+
* nothing is deferred.
|
|
69
70
|
* @param budgetMs - How much of the frame a call may spend. Non-positive means no limit.
|
|
70
71
|
* @returns Whether defs remain for a later drain.
|
|
71
72
|
*/
|