sceneInstrumentation.ts 21 KB

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