Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 增加编译耗时的统计 #657

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 2 additions & 11 deletions packages/effects-core/src/asset-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export class AssetManager implements Disposable {
const startTime = performance.now();
const timeInfoMessages: string[] = [];
const gpuInstance = renderer?.engine.gpuCapability;
const asyncShaderCompile = gpuInstance?.detail?.asyncShaderCompile ?? false;
const compressedTexture = gpuInstance?.detail.compressedTexture ?? COMPRESSED_TEXTURE.NONE;
const timeInfos: Record<string, number> = {};
let loadTimer: number;
Expand Down Expand Up @@ -173,7 +172,8 @@ export class AssetManager implements Disposable {
const [loadedBins, loadedImages] = await Promise.all([
hookTimeInfo('processBins', () => this.processBins(bins)),
hookTimeInfo('processImages', () => this.processImages(images, compressedTexture)),
hookTimeInfo(`${asyncShaderCompile ? 'async' : 'sync'}Compile`, () => this.precompile(compositions, pluginSystem, renderer, options)),
hookTimeInfo('precompile', () => this.precompile(compositions, pluginSystem, renderer, options)),
hookTimeInfo('processFontURL', () => this.processFontURL(fonts as spec.FontDefine[])),
]);

if (renderer) {
Expand All @@ -186,7 +186,6 @@ export class AssetManager implements Disposable {
}
}

await hookTimeInfo('processFontURL', () => this.processFontURL(fonts as spec.FontDefine[]));
const loadedTextures = await hookTimeInfo('processTextures', () => this.processTextures(loadedImages, loadedBins, jsonScene, renderer!.engine));

scene = {
Expand Down Expand Up @@ -231,15 +230,7 @@ export class AssetManager implements Disposable {
if (!renderer || !renderer.getShaderLibrary()) {
return;
}
const shaderLibrary = renderer?.getShaderLibrary();

await pluginSystem?.precompile(compositions, renderer, options);

await new Promise(resolve => {
shaderLibrary?.compileAllShaders(() => {
resolve(null);
});
});
}

private async processJSON (json: JSONValue) {
Expand Down
17 changes: 14 additions & 3 deletions packages/effects-core/src/composition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ import { EventEmitter } from './events';
import type { PostProcessVolume } from './components/post-process-volume';

export interface CompositionStatistic {
loadTime: number,
loadStart: number,
loadTime: number,
/**
* Shader 编译耗时
*/
compileTime: number,
/**
* 从加载到渲染第一帧的时间(含 Shader 编译)
*/
firstFrameTime: number,
precompileTime: number,
}

export interface MessageItem {
Expand Down Expand Up @@ -247,7 +253,12 @@ export class Composition extends EventEmitter<CompositionEvent<Composition>> imp
this.renderer = renderer;
this.texInfo = imageUsage ?? {};
this.event = event;
this.statistic = { loadTime: totalTime ?? 0, loadStart: scene.startTime ?? 0, firstFrameTime: 0, precompileTime: scene.timeInfos['asyncCompile'] ?? scene.timeInfos['syncCompile'] };
this.statistic = {
loadStart: scene.startTime ?? 0,
loadTime: totalTime ?? 0,
compileTime: 0,
firstFrameTime: 0,
};
this.reusable = reusable;
this.speed = speed;
this.autoRefTex = !this.keepResource && imageUsage && this.rootItem.endBehavior !== spec.EndBehavior.restart;
Expand Down
5 changes: 5 additions & 0 deletions packages/effects/src/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,8 @@ export class Player extends EventEmitter<PlayerEvent<Player>> implements Disposa
}
}

const compileStart = performance.now();

await new Promise(resolve => {
this.renderer.getShaderLibrary()?.compileAllShaders(() => {
resolve(null);
Expand All @@ -398,9 +400,12 @@ export class Player extends EventEmitter<PlayerEvent<Player>> implements Disposa
}

const firstFrameTime = performance.now() - last + composition.statistic.loadTime;
const compileTime = performance.now() - compileStart;

composition.statistic.firstFrameTime = firstFrameTime;
composition.statistic.compileTime = compileTime;
logger.info(`First frame: [${composition.name}]${firstFrameTime.toFixed(4)}ms.`);
logger.info(`Shader compile: [${composition.name}]${compileTime.toFixed(4)}ms.`);

return composition;
}
Expand Down
25 changes: 23 additions & 2 deletions web-packages/demo/html/single.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,34 @@
<style>
html, body, div, canvas { margin: 0; padding: 0; }
.container {
width: 375px;
height: 812px;
visibility: hidden;
opacity: 0;
width: 188px;
height: 334px;
position: fixed;
bottom: 0%;
left: 50%;
transform: translate(-50%, 0) scale(0);
transition: transform 0.5s ease-in-out;
background-color: rgba(0,0,0,255);
}
.container.active {
visibility: visible;
z-index: -1;
opacity: 1;
transform: translate(-50%, 0) scale(1);
}
ul {
background-color: rgba(255,255,255,0.5);
}
</style>
</head>
<body>
<h3>main</h3>
<ul id="J-statistic"></ul>
<div>
<button id="J-button" style="height: 32px; width: 100px;">播放</button>
</div>
<div class="container" id="J-container"></div>

<script type="module" src="../src/single.ts"></script>
Expand Down
57 changes: 46 additions & 11 deletions web-packages/demo/src/single.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,52 @@
import type { Composition } from '@galacean/effects';
import { Player } from '@galacean/effects';
import '@galacean/effects-plugin-spine';

const json = 'https://mdn.alipayobjects.com/mars/afts/file/A*CquWQrVCGyUAAAAAAAAAAAAADlB4AQ';
// 大量粒子
// const json = 'https://mdn.alipayobjects.com/mars/afts/file/A*aCeuQ5RQZj4AAAAAAAAAAAAADlB4AQ';
// 新年烟花
const json = [
'https://gw.alipayobjects.com/os/gltf-asset/mars-cli/ILDKKFUFMVJA/1705406034-80896.json',
'https://mdn.alipayobjects.com/graph_jupiter/afts/file/A*qTquTKYbk6EAAAAAAAAAAAAADsF2AQ',
];
// 混合测试
// const json = [
// 'https://mdn.alipayobjects.com/mars/afts/file/A*QyX8Rp-4fmUAAAAAAAAAAAAADlB4AQ',
// 'https://mdn.alipayobjects.com/mars/afts/file/A*bi3HRobVsk8AAAAAAAAAAAAADlB4AQ',
// 'https://mdn.alipayobjects.com/graph_jupiter/afts/file/A*sEdkT5cdXGEAAAAAAAAAAAAADsF2AQ',
// ];
// 塔奇
// const json = 'https://mdn.alipayobjects.com/mars/afts/file/A*uU2JRIjcLIcAAAAAAAAAAAAADlB4AQ';
// const json = 'https://gw.alipayobjects.com/os/gltf-asset/mars-cli/TAJIINQOUUKP/-799304223-0ee5d.json';
const container = document.getElementById('J-container');

(async () => {
try {
const player = new Player({
container,
});
document.getElementById('J-button')!.addEventListener('click', () => {
(async () => {
try {
container?.classList.add('active');

await player.loadScene(json);
} catch (e) {
console.error('biz', e);
}
})();
const player = new Player({
container,
// renderFramework: 'webgl2',
});
const compositions = await player.loadScene(Array.isArray(json) ? json : [json]) as unknown as Composition[];

compositions.forEach(composition => {
const div = document.createElement('div');

div.innerHTML = `>>>>> composition: ${composition.name}`;
document.getElementById('J-statistic')?.appendChild(div);

for (const key in composition.statistic) {
const p = document.createElement('li');

// @ts-expect-error
p.innerHTML = `${key}: ${composition.statistic[key]}`;
document.getElementById('J-statistic')?.appendChild(p);
}
});
} catch (e) {
console.error('biz', e);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enhance error handling for better debugging and user feedback

While the current error handling logs errors to the console, consider enhancing it to provide more detailed information and better user feedback.

Here's a suggested improvement:

} catch (e) {
  console.error('Error loading scene:', e);
  // Provide user feedback
  const errorMessage = e instanceof Error ? e.message : 'An unknown error occurred';
  alert(`Failed to load scene: ${errorMessage}`);
  // Reset UI state
  container?.classList.remove('active');
}

This enhancement:

  1. Provides more context in the console error.
  2. Displays a user-friendly error message.
  3. Resets the UI state in case of an error.

Additionally, consider implementing a more robust error handling strategy, such as using a dedicated error logging service for production environments.

})();
});