mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
perf(globe): less churn in movers and lines
Review of Tasks 2–3: - the mover store's instance checks no longer build arrays or closures per set() (orientation and colour checked field by field), and dirty() returns one reused range object; - Cesium models get their matrix and colour through scratch objects (Model.modelMatrix and Model.color copy what they are given) instead of a new Matrix4 and Color per placement; - a destroyed MoverSet releases its store (count 0, empty instance arrays, no pick ids) so a set object a layer still holds keeps no memory, and the Cesium parts drop their billboard, point and model lists; - (with the overlay commit) the Navara line viewport is updated in place. Node micro-measure, 10 000 instances set + packed per frame: 0.27-0.29 ms, about 1.7 KB per frame (0.17 B per instance), as before. Contract: Cesium 70/70, Navara 76/76.
This commit is contained in:
1 parent
d483e5897e
commit
39d522c9a9
3 files changed
+84
-17
No files matched your search
@@ -12,6 +12,8 @@ const scratchPosition = new Cesium.Cartesian3();
|
||||
const scratchColor = new Cesium.Color();
|
||||
const scratchQuaternion = new Cesium.Quaternion();
|
||||
const scratchRotation = new Cesium.Matrix3();
|
||||
// Model.modelMatrix and Model.color copy what they are given.
|
||||
const scratchModelMatrix = new Cesium.Matrix4();
|
||||
|
||||
/** The atlas cells as canvases, by key (a DOM canvas or image source). */
|
||||
async function cropAtlasCells(atlas, keys) {
|
||||
@@ -143,6 +145,9 @@ function spritePart(scene, options, store, factories, requestRender, owners) {
|
||||
},
|
||||
destroy() {
|
||||
destroyed = true;
|
||||
billboards.length = 0;
|
||||
shownCell.length = 0;
|
||||
cells = null;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -180,7 +185,9 @@ function pointPart(options, store, factories, requestRender, owners) {
|
||||
}
|
||||
requestRender('movers');
|
||||
},
|
||||
destroy() {},
|
||||
destroy() {
|
||||
points.length = 0;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -203,13 +210,12 @@ function modelPart(options, store, factories, requestRender, owners) {
|
||||
item.modelMatrix = Cesium.Matrix4.fromRotationTranslation(
|
||||
Cesium.Matrix3.fromQuaternion(scratchQuaternion, scratchRotation),
|
||||
readPosition(store, index),
|
||||
new Cesium.Matrix4(),
|
||||
scratchModelMatrix,
|
||||
);
|
||||
item.scale = store.scales[index];
|
||||
item.show = index < store.count && store.shows[index] === 1;
|
||||
item.id = store.pickIds[index];
|
||||
if (model.colorBlend)
|
||||
item.color = Cesium.Color.clone(readColor(store, index));
|
||||
if (model.colorBlend) item.color = readColor(store, index);
|
||||
};
|
||||
const ensure = (index) => {
|
||||
if (models[index] || loading[index]) return;
|
||||
@@ -258,6 +264,8 @@ function modelPart(options, store, factories, requestRender, owners) {
|
||||
},
|
||||
destroy() {
|
||||
destroyed = true;
|
||||
models.length = 0;
|
||||
loading.length = 0;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
+51
-12
@@ -150,17 +150,18 @@ export function normalizeMoverSetOptions(options) {
|
||||
export function createMoverStore(options) {
|
||||
const { capacity, cellKeys, kind } = options;
|
||||
const cellIndex = new Map(cellKeys.map((key, index) => [key, index]));
|
||||
const positions = new Float64Array(capacity * 3);
|
||||
const orientations = new Float64Array(capacity * 4);
|
||||
const colors = new Float32Array(capacity * 4).fill(1);
|
||||
const rotations = new Float32Array(capacity);
|
||||
const scales = new Float32Array(capacity).fill(1);
|
||||
const cells = new Uint16Array(capacity);
|
||||
const shows = new Uint8Array(capacity).fill(1);
|
||||
const pickIds = new Array(capacity);
|
||||
let positions = new Float64Array(capacity * 3);
|
||||
let orientations = new Float64Array(capacity * 4);
|
||||
let colors = new Float32Array(capacity * 4).fill(1);
|
||||
let rotations = new Float32Array(capacity);
|
||||
let scales = new Float32Array(capacity).fill(1);
|
||||
let cells = new Uint16Array(capacity);
|
||||
let shows = new Uint8Array(capacity).fill(1);
|
||||
let pickIds = new Array(capacity);
|
||||
for (let index = 0; index < capacity; index++)
|
||||
orientations[index * 4 + 3] = 1;
|
||||
let count = 0;
|
||||
const range = { from: 0, to: 0 };
|
||||
let dirtyFrom = Infinity;
|
||||
let dirtyTo = -Infinity;
|
||||
const touch = (from, to) => {
|
||||
@@ -189,7 +190,10 @@ export function createMoverStore(options) {
|
||||
orientation !== undefined &&
|
||||
!(
|
||||
isObject(orientation) &&
|
||||
['x', 'y', 'z', 'w'].every((axis) => isFiniteNumber(orientation[axis]))
|
||||
isFiniteNumber(orientation.x) &&
|
||||
isFiniteNumber(orientation.y) &&
|
||||
isFiniteNumber(orientation.z) &&
|
||||
isFiniteNumber(orientation.w)
|
||||
)
|
||||
)
|
||||
throw new TypeError('Mover orientation must be a quaternion');
|
||||
@@ -198,7 +202,10 @@ export function createMoverStore(options) {
|
||||
!(
|
||||
(Array.isArray(color) || ArrayBuffer.isView(color)) &&
|
||||
color.length === 4 &&
|
||||
Array.prototype.every.call(color, isFiniteNumber)
|
||||
isFiniteNumber(color[0]) &&
|
||||
isFiniteNumber(color[1]) &&
|
||||
isFiniteNumber(color[2]) &&
|
||||
isFiniteNumber(color[3])
|
||||
)
|
||||
)
|
||||
throw new TypeError('Mover color must be [r, g, b, a]');
|
||||
@@ -256,9 +263,40 @@ export function createMoverStore(options) {
|
||||
count = next;
|
||||
},
|
||||
positionsView: () => positions.subarray(0, count * 3),
|
||||
/**
|
||||
* Drops the instance arrays (a destroyed set): the count goes to 0 and
|
||||
* the arrays to empty ones, so a set object still held keeps no memory.
|
||||
*/
|
||||
release() {
|
||||
count = 0;
|
||||
positions = new Float64Array(0);
|
||||
orientations = new Float64Array(0);
|
||||
colors = new Float32Array(0);
|
||||
rotations = new Float32Array(0);
|
||||
scales = new Float32Array(0);
|
||||
cells = new Uint16Array(0);
|
||||
shows = new Uint8Array(0);
|
||||
pickIds = [];
|
||||
Object.assign(this, {
|
||||
positions,
|
||||
orientations,
|
||||
colors,
|
||||
rotations,
|
||||
scales,
|
||||
cells,
|
||||
shows,
|
||||
pickIds,
|
||||
});
|
||||
this.clean();
|
||||
},
|
||||
/** Indices changed since clean(), as [from, to), or null. */
|
||||
dirty: () =>
|
||||
dirtyFrom === Infinity ? null : { from: dirtyFrom, to: dirtyTo },
|
||||
/** The changed range (one object, reused: read it at once), or null. */
|
||||
dirty() {
|
||||
if (dirtyFrom === Infinity) return null;
|
||||
range.from = dirtyFrom;
|
||||
range.to = dirtyTo;
|
||||
return range;
|
||||
},
|
||||
clean() {
|
||||
dirtyFrom = Infinity;
|
||||
dirtyTo = -Infinity;
|
||||
@@ -296,6 +334,7 @@ export function createMoverSet(store, { commit, destroy }) {
|
||||
if (destroyed) return;
|
||||
destroyed = true;
|
||||
destroy();
|
||||
store.release?.();
|
||||
},
|
||||
isDestroyed: () => destroyed,
|
||||
};
|
||||
|
||||
@@ -170,7 +170,7 @@ test('the set facade forwards to the store and an engine commit, once destroyed
|
||||
);
|
||||
const calls = [];
|
||||
const set = createMoverSet(store, {
|
||||
commit: () => calls.push(['commit', store.dirty()]),
|
||||
commit: () => calls.push(['commit', { ...store.dirty() }]),
|
||||
destroy: () => calls.push(['destroy']),
|
||||
});
|
||||
set.set(0, { position: { x: 1, y: 2, z: 3 } });
|
||||
@@ -187,3 +187,23 @@ test('the set facade forwards to the store and an engine commit, once destroyed
|
||||
assert.throws(() => set.set(0, {}), /destroyed/);
|
||||
assert.throws(() => set.commit(), /destroyed/);
|
||||
});
|
||||
|
||||
test('a destroyed set releases its instance arrays', () => {
|
||||
const store = createMoverStore(
|
||||
normalizeMoverSetOptions({
|
||||
id: 'r',
|
||||
kind: 'point',
|
||||
capacity: 1000,
|
||||
point: { sizePx: 2 },
|
||||
}),
|
||||
);
|
||||
const set = createMoverSet(store, { commit() {}, destroy() {} });
|
||||
set.set(0, { position: { x: 1, y: 2, z: 3 }, pickId: 'p' });
|
||||
set.setCount(1);
|
||||
set.destroy();
|
||||
assert.equal(store.count, 0);
|
||||
assert.equal(store.positions.length, 0);
|
||||
assert.equal(store.pickIds.length, 0);
|
||||
assert.equal(set.positionsView().length, 0);
|
||||
assert.equal(store.dirty(), null);
|
||||
});
|
||||
Reference in new issue
Block a user