fix: bind performance evidence to production resources

This commit is contained in:
2026-09-02 08:53:00 +03:00
parent 5b7e47c2a2
commit e3ac3a4db4
23 changed files with 642 additions and 60 deletions

View File

@@ -5,6 +5,7 @@ import { renderQualityFor } from '@/scene/render-quality';
import { createChaseCamera } from '@/scene/world/environment';
import { createCar } from '@/scene/world/car';
import { routeLabelFor } from '@/scene/world/sign';
import { evaluateRuntimeTraceBudgetEvidence } from '../../scripts/lib/bundle-budgets.mjs';
describe('SceneResourceBag', () => {
it.each([
@@ -90,6 +91,62 @@ describe('SceneResourceBag', () => {
bag.dispose();
expect(cancelFrame).toHaveBeenCalledOnce();
});
it('derives allocation bytes from the actual owned geometry, texture, and render target', () => {
const bag = new SceneResourceBag();
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(12), 3));
geometry.setIndex(new THREE.BufferAttribute(new Uint16Array(6), 1));
bag.own('geometry', geometry);
bag.own('texture', new THREE.DataTexture(new Uint8Array(4 * 8 * 4), 4, 8));
bag.own('target', new THREE.WebGLRenderTarget(16, 8, { depthBuffer: true }));
const snapshot = bag.gpuBudgetSnapshot({
tier: 'low',
defaultFramebuffer: { width: 32, height: 16, bytesPerPixel: 4, attachments: 2, samples: 1 },
});
expect(snapshot.geometryBytes).toBe(12 * 4 + 6 * 2);
expect(snapshot.textures[0]).toMatchObject({ width: 4, height: 8, bytesPerPixel: 4, layers: 1 });
expect(snapshot.renderTargets).toEqual(expect.arrayContaining([
expect.objectContaining({ width: 16, height: 8, attachments: 2, samples: 1 }),
expect.objectContaining({ id: 'default-framebuffer', width: 32, height: 16 }),
]));
});
it('changes the production ledger when an actual geometry allocation is added', () => {
const bag = new SceneResourceBag();
const before = bag.gpuBudgetSnapshot({ tier: 'high', defaultFramebuffer: { width: 1, height: 1, bytesPerPixel: 4, attachments: 2, samples: 1 } });
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(30), 3));
bag.own('geometry', geometry);
const after = bag.gpuBudgetSnapshot({ tier: 'high', defaultFramebuffer: { width: 1, height: 1, bytesPerPixel: 4, attachments: 2, samples: 1 } });
expect(after.geometryBytes - before.geometryBytes).toBe(30 * 4);
});
it('fails from actual oversized production texture and render-target allocations', () => {
const textureBag = new SceneResourceBag();
const canvas = document.createElement('canvas');
canvas.width = 4_096;
canvas.height = 4_096;
textureBag.own('texture', new THREE.CanvasTexture(canvas));
const textureResult = evaluateRuntimeTraceBudgetEvidence({
schema: 'portfolio-runtime-trace-evidence/v1',
peakRequests: { imageScene: 0, video: 0 },
allocation: textureBag.gpuBudgetSnapshot({ tier: 'low', defaultFramebuffer: { width: 1, height: 1, bytesPerPixel: 4, attachments: 2, samples: 1 } }),
});
expect(textureResult.violations.map((item) => item.budget)).toEqual(expect.arrayContaining(['mobileTextureDimension', 'lowTierGpuEstimate']));
const targetBag = new SceneResourceBag();
targetBag.own('target', new THREE.WebGLRenderTarget(4_096, 4_096, { depthBuffer: true }));
const targetResult = evaluateRuntimeTraceBudgetEvidence({
schema: 'portfolio-runtime-trace-evidence/v1',
peakRequests: { imageScene: 0, video: 0 },
allocation: targetBag.gpuBudgetSnapshot({ tier: 'low', defaultFramebuffer: { width: 1, height: 1, bytesPerPixel: 4, attachments: 2, samples: 1 } }),
});
expect(targetResult.violations.map((item) => item.budget)).toContain('lowTierGpuEstimate');
});
});
describe('scene render quality', () => {