diff --git a/packages/effects-core/src/asset-manager.ts b/packages/effects-core/src/asset-manager.ts index 7bb8c37ef..b201ea589 100644 --- a/packages/effects-core/src/asset-manager.ts +++ b/packages/effects-core/src/asset-manager.ts @@ -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 = {}; let loadTimer: number; @@ -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) { @@ -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 = { @@ -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) { diff --git a/packages/effects-core/src/composition.ts b/packages/effects-core/src/composition.ts index 28bd537d1..c7672bab3 100644 --- a/packages/effects-core/src/composition.ts +++ b/packages/effects-core/src/composition.ts @@ -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 { @@ -247,7 +253,12 @@ export class Composition extends EventEmitter> 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; diff --git a/packages/effects/src/player.ts b/packages/effects/src/player.ts index 16c9b5a9b..0a215a28a 100644 --- a/packages/effects/src/player.ts +++ b/packages/effects/src/player.ts @@ -384,6 +384,8 @@ export class Player extends EventEmitter> implements Disposa } } + const compileStart = performance.now(); + await new Promise(resolve => { this.renderer.getShaderLibrary()?.compileAllShaders(() => { resolve(null); @@ -397,10 +399,13 @@ export class Player extends EventEmitter> implements Disposa composition.pause(); } - const firstFrameTime = performance.now() - last + composition.statistic.loadTime; + const firstFrameTime = performance.now() - last; + 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; } diff --git a/web-packages/demo/html/shader-compile.html b/web-packages/demo/html/shader-compile.html new file mode 100644 index 000000000..f0f510ec4 --- /dev/null +++ b/web-packages/demo/html/shader-compile.html @@ -0,0 +1,41 @@ + + + + + + Shader 编译测试 - demo + + + +
+
+ +
+
+ + + + diff --git a/web-packages/demo/index.html b/web-packages/demo/index.html index 6fcef3b31..3a3648eb5 100644 --- a/web-packages/demo/index.html +++ b/web-packages/demo/index.html @@ -13,6 +13,7 @@
单项目测试 后处理测试 + Shader 编译测试 Dashboard Interactive 压缩纹理 diff --git a/web-packages/demo/src/shader-compile.ts b/web-packages/demo/src/shader-compile.ts new file mode 100644 index 000000000..0cafb59d8 --- /dev/null +++ b/web-packages/demo/src/shader-compile.ts @@ -0,0 +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*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'); + +document.getElementById('J-button')!.addEventListener('click', () => { + (async () => { + try { + container?.classList.add('active'); + + 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 dt = document.createElement('dt'); + + dt.innerHTML = `>>> composition: ${composition.name}`; + document.getElementById('J-statistic')?.appendChild(dt); + + for (const key in composition.statistic) { + const p = document.createElement('dd'); + + // @ts-expect-error + p.innerHTML = `${key}: ${composition.statistic[key]}`; + document.getElementById('J-statistic')?.appendChild(p); + } + }); + } catch (e) { + console.error('biz', e); + } + })(); +}); diff --git a/web-packages/demo/vite.config.js b/web-packages/demo/vite.config.js index da45816a0..9b16cbe60 100644 --- a/web-packages/demo/vite.config.js +++ b/web-packages/demo/vite.config.js @@ -24,6 +24,7 @@ export default defineConfig(({ mode }) => { 'dynamic-image': resolve(__dirname, 'html/dynamic-image.html'), 'dynamic-video': resolve(__dirname, 'html/dynamic-video.html'), 'render-level': resolve(__dirname, 'html/render-level.html'), + 'shader-compile': resolve(__dirname, 'html/shader-compile.html'), 'local-file': resolve(__dirname, 'html/local-file.html'), 'post-processing': resolve(__dirname, 'html/post-processing.html'), 'single': resolve(__dirname, 'html/single.html'),