sceneInstrumentation.ts 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. import { Tools } from "../Misc/tools";
  2. import { Observer } from "../Misc/observable";
  3. import { Nullable } from "../types";
  4. import { Camera } from "../Cameras/camera";
  5. import { Scene, IDisposable } from "../scene";
  6. import { PerfCounter } from '../Misc/perfCounter';
  7. /**
  8. * This class can be used to get instrumentation data from a Babylon engine
  9. * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
  10. */
  11. export class SceneInstrumentation implements IDisposable {
  12. private _captureActiveMeshesEvaluationTime = false;
  13. private _activeMeshesEvaluationTime = new PerfCounter();
  14. private _captureRenderTargetsRenderTime = false;
  15. private _renderTargetsRenderTime = new PerfCounter();
  16. private _captureFrameTime = false;
  17. private _frameTime = new PerfCounter();
  18. private _captureRenderTime = false;
  19. private _renderTime = new PerfCounter();
  20. private _captureInterFrameTime = false;
  21. private _interFrameTime = new PerfCounter();
  22. private _captureParticlesRenderTime = false;
  23. private _particlesRenderTime = new PerfCounter();
  24. private _captureSpritesRenderTime = false;
  25. private _spritesRenderTime = new PerfCounter();
  26. private _capturePhysicsTime = false;
  27. private _physicsTime = new PerfCounter();
  28. private _captureAnimationsTime = false;
  29. private _animationsTime = new PerfCounter();
  30. private _captureCameraRenderTime = false;
  31. private _cameraRenderTime = new PerfCounter();
  32. // Observers
  33. private _onBeforeActiveMeshesEvaluationObserver: Nullable<Observer<Scene>> = null;
  34. private _onAfterActiveMeshesEvaluationObserver: Nullable<Observer<Scene>> = null;
  35. private _onBeforeRenderTargetsRenderObserver: Nullable<Observer<Scene>> = null;
  36. private _onAfterRenderTargetsRenderObserver: Nullable<Observer<Scene>> = null;
  37. private _onAfterRenderObserver: Nullable<Observer<Scene>> = null;
  38. private _onBeforeDrawPhaseObserver: Nullable<Observer<Scene>> = null;
  39. private _onAfterDrawPhaseObserver: Nullable<Observer<Scene>> = null;
  40. private _onBeforeAnimationsObserver: Nullable<Observer<Scene>> = null;
  41. private _onBeforeParticlesRenderingObserver: Nullable<Observer<Scene>> = null;
  42. private _onAfterParticlesRenderingObserver: Nullable<Observer<Scene>> = null;
  43. private _onBeforeSpritesRenderingObserver: Nullable<Observer<Scene>> = null;
  44. private _onAfterSpritesRenderingObserver: Nullable<Observer<Scene>> = null;
  45. private _onBeforePhysicsObserver: Nullable<Observer<Scene>> = null;
  46. private _onAfterPhysicsObserver: Nullable<Observer<Scene>> = null;
  47. private _onAfterAnimationsObserver: Nullable<Observer<Scene>> = null;
  48. private _onBeforeCameraRenderObserver: Nullable<Observer<Camera>> = null;
  49. private _onAfterCameraRenderObserver: Nullable<Observer<Camera>> = null;
  50. // Properties
  51. /**
  52. * Gets the perf counter used for active meshes evaluation time
  53. */
  54. public get activeMeshesEvaluationTimeCounter(): PerfCounter {
  55. return this._activeMeshesEvaluationTime;
  56. }
  57. /**
  58. * Gets the active meshes evaluation time capture status
  59. */
  60. public get captureActiveMeshesEvaluationTime(): boolean {
  61. return this._captureActiveMeshesEvaluationTime;
  62. }
  63. /**
  64. * Enable or disable the active meshes evaluation time capture
  65. */
  66. public set captureActiveMeshesEvaluationTime(value: boolean) {
  67. if (value === this._captureActiveMeshesEvaluationTime) {
  68. return;
  69. }
  70. this._captureActiveMeshesEvaluationTime = value;
  71. if (value) {
  72. this._onBeforeActiveMeshesEvaluationObserver = this.scene.onBeforeActiveMeshesEvaluationObservable.add(() => {
  73. Tools.StartPerformanceCounter("Active meshes evaluation");
  74. this._activeMeshesEvaluationTime.beginMonitoring();
  75. });
  76. this._onAfterActiveMeshesEvaluationObserver = this.scene.onAfterActiveMeshesEvaluationObservable.add(() => {
  77. Tools.EndPerformanceCounter("Active meshes evaluation");
  78. this._activeMeshesEvaluationTime.endMonitoring();
  79. });
  80. } else {
  81. this.scene.onBeforeActiveMeshesEvaluationObservable.remove(this._onBeforeActiveMeshesEvaluationObserver);
  82. this._onBeforeActiveMeshesEvaluationObserver = null;
  83. this.scene.onAfterActiveMeshesEvaluationObservable.remove(this._onAfterActiveMeshesEvaluationObserver);
  84. this._onAfterActiveMeshesEvaluationObserver = null;
  85. }
  86. }
  87. /**
  88. * Gets the perf counter used for render targets render time
  89. */
  90. public get renderTargetsRenderTimeCounter(): PerfCounter {
  91. return this._renderTargetsRenderTime;
  92. }
  93. /**
  94. * Gets the render targets render time capture status
  95. */
  96. public get captureRenderTargetsRenderTime(): boolean {
  97. return this._captureRenderTargetsRenderTime;
  98. }
  99. /**
  100. * Enable or disable the render targets render time capture
  101. */
  102. public set captureRenderTargetsRenderTime(value: boolean) {
  103. if (value === this._captureRenderTargetsRenderTime) {
  104. return;
  105. }
  106. this._captureRenderTargetsRenderTime = value;
  107. if (value) {
  108. this._onBeforeRenderTargetsRenderObserver = this.scene.onBeforeRenderTargetsRenderObservable.add(() => {
  109. Tools.StartPerformanceCounter("Render targets rendering");
  110. this._renderTargetsRenderTime.beginMonitoring();
  111. });
  112. this._onAfterRenderTargetsRenderObserver = this.scene.onAfterRenderTargetsRenderObservable.add(() => {
  113. Tools.EndPerformanceCounter("Render targets rendering");
  114. this._renderTargetsRenderTime.endMonitoring(false);
  115. });
  116. } else {
  117. this.scene.onBeforeRenderTargetsRenderObservable.remove(this._onBeforeRenderTargetsRenderObserver);
  118. this._onBeforeRenderTargetsRenderObserver = null;
  119. this.scene.onAfterRenderTargetsRenderObservable.remove(this._onAfterRenderTargetsRenderObserver);
  120. this._onAfterRenderTargetsRenderObserver = null;
  121. }
  122. }
  123. /**
  124. * Gets the perf counter used for particles render time
  125. */
  126. public get particlesRenderTimeCounter(): PerfCounter {
  127. return this._particlesRenderTime;
  128. }
  129. /**
  130. * Gets the particles render time capture status
  131. */
  132. public get captureParticlesRenderTime(): boolean {
  133. return this._captureParticlesRenderTime;
  134. }
  135. /**
  136. * Enable or disable the particles render time capture
  137. */
  138. public set captureParticlesRenderTime(value: boolean) {
  139. if (value === this._captureParticlesRenderTime) {
  140. return;
  141. }
  142. this._captureParticlesRenderTime = value;
  143. if (value) {
  144. this._onBeforeParticlesRenderingObserver = this.scene.onBeforeParticlesRenderingObservable.add(() => {
  145. Tools.StartPerformanceCounter("Particles");
  146. this._particlesRenderTime.beginMonitoring();
  147. });
  148. this._onAfterParticlesRenderingObserver = this.scene.onAfterParticlesRenderingObservable.add(() => {
  149. Tools.EndPerformanceCounter("Particles");
  150. this._particlesRenderTime.endMonitoring(false);
  151. });
  152. } else {
  153. this.scene.onBeforeParticlesRenderingObservable.remove(this._onBeforeParticlesRenderingObserver);
  154. this._onBeforeParticlesRenderingObserver = null;
  155. this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver);
  156. this._onAfterParticlesRenderingObserver = null;
  157. }
  158. }
  159. /**
  160. * Gets the perf counter used for sprites render time
  161. */
  162. public get spritesRenderTimeCounter(): PerfCounter {
  163. return this._spritesRenderTime;
  164. }
  165. /**
  166. * Gets the sprites render time capture status
  167. */
  168. public get captureSpritesRenderTime(): boolean {
  169. return this._captureSpritesRenderTime;
  170. }
  171. /**
  172. * Enable or disable the sprites render time capture
  173. */
  174. public set captureSpritesRenderTime(value: boolean) {
  175. if (value === this._captureSpritesRenderTime) {
  176. return;
  177. }
  178. this._captureSpritesRenderTime = value;
  179. if (!this.scene.spriteManagers) {
  180. return;
  181. }
  182. if (value) {
  183. this._onBeforeSpritesRenderingObserver = this.scene.onBeforeSpritesRenderingObservable.add(() => {
  184. Tools.StartPerformanceCounter("Sprites");
  185. this._spritesRenderTime.beginMonitoring();
  186. });
  187. this._onAfterSpritesRenderingObserver = this.scene.onAfterSpritesRenderingObservable.add(() => {
  188. Tools.EndPerformanceCounter("Sprites");
  189. this._spritesRenderTime.endMonitoring(false);
  190. });
  191. } else {
  192. this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
  193. this._onBeforeSpritesRenderingObserver = null;
  194. this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
  195. this._onAfterSpritesRenderingObserver = null;
  196. }
  197. }
  198. /**
  199. * Gets the perf counter used for physics time
  200. */
  201. public get physicsTimeCounter(): PerfCounter {
  202. return this._physicsTime;
  203. }
  204. /**
  205. * Gets the physics time capture status
  206. */
  207. public get capturePhysicsTime(): boolean {
  208. return this._capturePhysicsTime;
  209. }
  210. /**
  211. * Enable or disable the physics time capture
  212. */
  213. public set capturePhysicsTime(value: boolean) {
  214. if (value === this._capturePhysicsTime) {
  215. return;
  216. }
  217. if (!this.scene.onBeforePhysicsObservable) {
  218. return;
  219. }
  220. this._capturePhysicsTime = value;
  221. if (value) {
  222. this._onBeforePhysicsObserver = this.scene.onBeforePhysicsObservable.add(() => {
  223. Tools.StartPerformanceCounter("Physics");
  224. this._physicsTime.beginMonitoring();
  225. });
  226. this._onAfterPhysicsObserver = this.scene.onAfterPhysicsObservable.add(() => {
  227. Tools.EndPerformanceCounter("Physics");
  228. this._physicsTime.endMonitoring();
  229. });
  230. } else {
  231. this.scene.onBeforePhysicsObservable.remove(this._onBeforePhysicsObserver);
  232. this._onBeforePhysicsObserver = null;
  233. this.scene.onAfterPhysicsObservable.remove(this._onAfterPhysicsObserver);
  234. this._onAfterPhysicsObserver = null;
  235. }
  236. }
  237. /**
  238. * Gets the perf counter used for animations time
  239. */
  240. public get animationsTimeCounter(): PerfCounter {
  241. return this._animationsTime;
  242. }
  243. /**
  244. * Gets the animations time capture status
  245. */
  246. public get captureAnimationsTime(): boolean {
  247. return this._captureAnimationsTime;
  248. }
  249. /**
  250. * Enable or disable the animations time capture
  251. */
  252. public set captureAnimationsTime(value: boolean) {
  253. if (value === this._captureAnimationsTime) {
  254. return;
  255. }
  256. this._captureAnimationsTime = value;
  257. if (value) {
  258. this._onAfterAnimationsObserver = this.scene.onAfterAnimationsObservable.add(() => {
  259. this._animationsTime.endMonitoring();
  260. });
  261. } else {
  262. this.scene.onAfterAnimationsObservable.remove(this._onAfterAnimationsObserver);
  263. this._onAfterAnimationsObserver = null;
  264. }
  265. }
  266. /**
  267. * Gets the perf counter used for frame time capture
  268. */
  269. public get frameTimeCounter(): PerfCounter {
  270. return this._frameTime;
  271. }
  272. /**
  273. * Gets the frame time capture status
  274. */
  275. public get captureFrameTime(): boolean {
  276. return this._captureFrameTime;
  277. }
  278. /**
  279. * Enable or disable the frame time capture
  280. */
  281. public set captureFrameTime(value: boolean) {
  282. this._captureFrameTime = value;
  283. }
  284. /**
  285. * Gets the perf counter used for inter-frames time capture
  286. */
  287. public get interFrameTimeCounter(): PerfCounter {
  288. return this._interFrameTime;
  289. }
  290. /**
  291. * Gets the inter-frames time capture status
  292. */
  293. public get captureInterFrameTime(): boolean {
  294. return this._captureInterFrameTime;
  295. }
  296. /**
  297. * Enable or disable the inter-frames time capture
  298. */
  299. public set captureInterFrameTime(value: boolean) {
  300. this._captureInterFrameTime = value;
  301. }
  302. /**
  303. * Gets the perf counter used for render time capture
  304. */
  305. public get renderTimeCounter(): PerfCounter {
  306. return this._renderTime;
  307. }
  308. /**
  309. * Gets the render time capture status
  310. */
  311. public get captureRenderTime(): boolean {
  312. return this._captureRenderTime;
  313. }
  314. /**
  315. * Enable or disable the render time capture
  316. */
  317. public set captureRenderTime(value: boolean) {
  318. if (value === this._captureRenderTime) {
  319. return;
  320. }
  321. this._captureRenderTime = value;
  322. if (value) {
  323. this._onBeforeDrawPhaseObserver = this.scene.onBeforeDrawPhaseObservable.add(() => {
  324. this._renderTime.beginMonitoring();
  325. Tools.StartPerformanceCounter("Main render");
  326. });
  327. this._onAfterDrawPhaseObserver = this.scene.onAfterDrawPhaseObservable.add(() => {
  328. this._renderTime.endMonitoring(false);
  329. Tools.EndPerformanceCounter("Main render");
  330. });
  331. } else {
  332. this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver);
  333. this._onBeforeDrawPhaseObserver = null;
  334. this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver);
  335. this._onAfterDrawPhaseObserver = null;
  336. }
  337. }
  338. /**
  339. * Gets the perf counter used for camera render time capture
  340. */
  341. public get cameraRenderTimeCounter(): PerfCounter {
  342. return this._cameraRenderTime;
  343. }
  344. /**
  345. * Gets the camera render time capture status
  346. */
  347. public get captureCameraRenderTime(): boolean {
  348. return this._captureCameraRenderTime;
  349. }
  350. /**
  351. * Enable or disable the camera render time capture
  352. */
  353. public set captureCameraRenderTime(value: boolean) {
  354. if (value === this._captureCameraRenderTime) {
  355. return;
  356. }
  357. this._captureCameraRenderTime = value;
  358. if (value) {
  359. this._onBeforeCameraRenderObserver = this.scene.onBeforeCameraRenderObservable.add((camera) => {
  360. this._cameraRenderTime.beginMonitoring();
  361. Tools.StartPerformanceCounter(`Rendering camera ${camera.name}`);
  362. });
  363. this._onAfterCameraRenderObserver = this.scene.onAfterCameraRenderObservable.add((camera) => {
  364. this._cameraRenderTime.endMonitoring(false);
  365. Tools.EndPerformanceCounter(`Rendering camera ${camera.name}`);
  366. });
  367. } else {
  368. this.scene.onBeforeCameraRenderObservable.remove(this._onBeforeCameraRenderObserver);
  369. this._onBeforeCameraRenderObserver = null;
  370. this.scene.onAfterCameraRenderObservable.remove(this._onAfterCameraRenderObserver);
  371. this._onAfterCameraRenderObserver = null;
  372. }
  373. }
  374. /**
  375. * Gets the perf counter used for draw calls
  376. */
  377. public get drawCallsCounter(): PerfCounter {
  378. return this.scene.getEngine()._drawCalls;
  379. }
  380. /**
  381. * Instantiates a new scene instrumentation.
  382. * This class can be used to get instrumentation data from a Babylon engine
  383. * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
  384. * @param scene Defines the scene to instrument
  385. */
  386. public constructor(
  387. /**
  388. * Defines the scene to instrument
  389. */
  390. public scene: Scene) {
  391. // Before render
  392. this._onBeforeAnimationsObserver = scene.onBeforeAnimationsObservable.add(() => {
  393. if (this._captureActiveMeshesEvaluationTime) {
  394. this._activeMeshesEvaluationTime.fetchNewFrame();
  395. }
  396. if (this._captureRenderTargetsRenderTime) {
  397. this._renderTargetsRenderTime.fetchNewFrame();
  398. }
  399. if (this._captureFrameTime) {
  400. Tools.StartPerformanceCounter("Scene rendering");
  401. this._frameTime.beginMonitoring();
  402. }
  403. if (this._captureInterFrameTime) {
  404. this._interFrameTime.endMonitoring();
  405. }
  406. if (this._captureParticlesRenderTime) {
  407. this._particlesRenderTime.fetchNewFrame();
  408. }
  409. if (this._captureSpritesRenderTime) {
  410. this._spritesRenderTime.fetchNewFrame();
  411. }
  412. if (this._captureAnimationsTime) {
  413. this._animationsTime.beginMonitoring();
  414. }
  415. this.scene.getEngine()._drawCalls.fetchNewFrame();
  416. });
  417. // After render
  418. this._onAfterRenderObserver = scene.onAfterRenderObservable.add(() => {
  419. if (this._captureFrameTime) {
  420. Tools.EndPerformanceCounter("Scene rendering");
  421. this._frameTime.endMonitoring();
  422. }
  423. if (this._captureRenderTime) {
  424. this._renderTime.endMonitoring(false);
  425. }
  426. if (this._captureInterFrameTime) {
  427. this._interFrameTime.beginMonitoring();
  428. }
  429. });
  430. }
  431. /**
  432. * Dispose and release associated resources.
  433. */
  434. public dispose() {
  435. this.scene.onAfterRenderObservable.remove(this._onAfterRenderObserver);
  436. this._onAfterRenderObserver = null;
  437. this.scene.onBeforeActiveMeshesEvaluationObservable.remove(this._onBeforeActiveMeshesEvaluationObserver);
  438. this._onBeforeActiveMeshesEvaluationObserver = null;
  439. this.scene.onAfterActiveMeshesEvaluationObservable.remove(this._onAfterActiveMeshesEvaluationObserver);
  440. this._onAfterActiveMeshesEvaluationObserver = null;
  441. this.scene.onBeforeRenderTargetsRenderObservable.remove(this._onBeforeRenderTargetsRenderObserver);
  442. this._onBeforeRenderTargetsRenderObserver = null;
  443. this.scene.onAfterRenderTargetsRenderObservable.remove(this._onAfterRenderTargetsRenderObserver);
  444. this._onAfterRenderTargetsRenderObserver = null;
  445. this.scene.onBeforeAnimationsObservable.remove(this._onBeforeAnimationsObserver);
  446. this._onBeforeAnimationsObserver = null;
  447. this.scene.onBeforeParticlesRenderingObservable.remove(this._onBeforeParticlesRenderingObserver);
  448. this._onBeforeParticlesRenderingObserver = null;
  449. this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver);
  450. this._onAfterParticlesRenderingObserver = null;
  451. if (this._onBeforeSpritesRenderingObserver) {
  452. this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
  453. this._onBeforeSpritesRenderingObserver = null;
  454. }
  455. if (this._onAfterSpritesRenderingObserver) {
  456. this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
  457. this._onAfterSpritesRenderingObserver = null;
  458. }
  459. this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver);
  460. this._onBeforeDrawPhaseObserver = null;
  461. this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver);
  462. this._onAfterDrawPhaseObserver = null;
  463. if (this._onBeforePhysicsObserver) {
  464. this.scene.onBeforePhysicsObservable.remove(this._onBeforePhysicsObserver);
  465. this._onBeforePhysicsObserver = null;
  466. }
  467. if (this._onAfterPhysicsObserver) {
  468. this.scene.onAfterPhysicsObservable.remove(this._onAfterPhysicsObserver);
  469. this._onAfterPhysicsObserver = null;
  470. }
  471. this.scene.onAfterAnimationsObservable.remove(this._onAfterAnimationsObserver);
  472. this._onAfterAnimationsObserver = null;
  473. this.scene.onBeforeCameraRenderObservable.remove(this._onBeforeCameraRenderObserver);
  474. this._onBeforeCameraRenderObserver = null;
  475. this.scene.onAfterCameraRenderObservable.remove(this._onAfterCameraRenderObserver);
  476. this._onAfterCameraRenderObserver = null;
  477. (<any>this.scene) = null;
  478. }
  479. }