Skip to content

Instantly share code, notes, and snippets.

@cgcostume
Created July 17, 2025 16:34
Show Gist options
  • Save cgcostume/44d44d204e5c2df521070fcc7c080f58 to your computer and use it in GitHub Desktop.
Save cgcostume/44d44d204e5c2df521070fcc7c080f58 to your computer and use it in GitHub Desktop.
Progressive LMV-Rendering Expectations
// This script helps to verify the following assumption:
//
// given:
// - a single camera change
// - a small model that can be rendered within a single tick
// expected:
// - a single tick per camera change
// - two FINAL_FRAME_RENDERED_CHANGED_EVENT events per change
// - one RENDER_PRESENTED_EVENT event per change
// - one renderSome call per change
// This helped to verify https://git.autodesk.com/A360/firefly.js/pull/9443
async function testProgressiveRenderingIssue(viewer, targetFPS = 30, numIterations = 4, offset = 1.0) {
console.log(` -- progressive rendering test for ${numIterations} camera changes...`);
const primitiveCounter = await viewer.loadExtension('Autodesk.DeveloperTools.PrimitiveCounter');
primitiveCounter.activate();
primitiveCounter.clearCache();
viewer.impl.setFPSTargets(targetFPS, targetFPS, targetFPS);
const { FunctionIntrusion, HookType } = await import('/src/tools/FunctionIntrusion.js');
const implIntrusion = new FunctionIntrusion(viewer.impl);
const renderSceneIntrusion = new FunctionIntrusion(viewer.impl.modelQueue());
let renderSomeCallCount = 0;
let tickCallCount = 0;
implIntrusion.addHook('tick', () => tickCallCount++, HookType.Before);
renderSceneIntrusion.addHook('renderSome', () => renderSomeCallCount++, HookType.Before);
const results = [];
let currentIteration = 0;
let currentIterationData = null;
let totalRenderPresentedCount = 0;
let totalFrameCount = 0;
const onRenderPresented = (event) => {
if (!currentIterationData) return;
currentIterationData.renderPresentedCount++;
totalRenderPresentedCount++;
console.log(`RENDER_PRESENTED #${currentIterationData.renderPresentedCount}`, event);
};
const onFinalFrameChanged = (event) => {
if (!currentIterationData) return;
currentIterationData.frameCount++;
totalFrameCount++;
const finalFrame = event.value?.finalFrame;
console.log(`FINAL_FRAME_CHANGED #${currentIterationData.frameCount}`, event.value);
if (!finalFrame) return;
const finalCounts = primitiveCounter.getAccumulatedTickCounts(true);
const result = {
iteration: currentIteration + 1,
finalCounts,
tickCallsThisIteration: tickCallCount - currentIterationData.startTickCount,
renderSomeCallsThisIteration: renderSomeCallCount - currentIterationData.startRenderSomeCount,
renderPresentedCount: currentIterationData.renderPresentedCount,
frameCount: currentIterationData.frameCount
};
console.log(`ITERATION ${currentIteration + 1} done:`, result);
results.push(result);
currentIterationData.resolve(result);
};
viewer.addEventListener(Autodesk.Viewing.RENDER_PRESENTED_EVENT, onRenderPresented);
viewer.addEventListener(Autodesk.Viewing.FINAL_FRAME_RENDERED_CHANGED_EVENT, onFinalFrameChanged);
for (let i = 0; i < numIterations; ++i) {
console.log(` -- iteration ${i + 1}/${numIterations}`);
currentIteration = i;
const camera = viewer.getCamera();
const newPosition = {
x: camera.position.x + (Math.random() - 0.5) * offset,
y: camera.position.y + (Math.random() - 0.5) * offset,
z: camera.position.z + (Math.random() - 0.5) * offset
};
const startTickCount = tickCallCount;
const startRenderSomeCount = renderSomeCallCount;
primitiveCounter.getAccumulatedTickCounts(true);
const iterationResult = await new Promise((resolve) => {
currentIterationData = {
renderPresentedCount: 0,
frameCount: 0,
startTickCount,
startRenderSomeCount,
resolve
};
viewer.navigation.setView(new THREE.Vector3(newPosition.x, newPosition.y, newPosition.z), camera.target, camera.up);
});
// if (i < numIterations - 1) { await new Promise(resolve => setTimeout(resolve, 300)); }
}
viewer.removeEventListener(Autodesk.Viewing.RENDER_PRESENTED_EVENT, onRenderPresented);
viewer.removeEventListener(Autodesk.Viewing.FINAL_FRAME_RENDERED_CHANGED_EVENT, onFinalFrameChanged);
implIntrusion.removeAllHooks();
renderSceneIntrusion.removeAllHooks();
primitiveCounter.deactivate();
console.log(' -- Summary');
console.log(` -- Total tick calls across all iterations: ${tickCallCount}`);
console.log(` -- Total renderSome calls across all iterations: ${renderSomeCallCount}`);
const avgRenderPresented = totalRenderPresentedCount / numIterations;
const avgFrameEvents = totalFrameCount / numIterations;
console.log(` -- Total render presented events: ${totalRenderPresentedCount}`);
console.log(` -- Total final frame events: ${totalFrameCount}`);
console.log(` -- Average render presented per iteration: ${avgRenderPresented.toFixed(2)}`);
console.log(` -- Average final frame events per iteration: ${avgFrameEvents.toFixed(2)}`);
}
testProgressiveRenderingIssue(NOP_VIEWER, 30, 4, 100.0);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment