StatsTab.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. module INSPECTOR {
  2. export class StatsTab extends Tab {
  3. private _inspector : Inspector;
  4. /**
  5. * Properties in this array will be updated
  6. * in a render loop - Mostly stats properties
  7. */
  8. private _updatableProperties : Array<{elem:HTMLElement, updateFct : () => string}> = [];
  9. private _scene : BABYLON.Scene;
  10. private _engine : BABYLON.Engine;
  11. private _glInfo : any;
  12. private _updateLoopHandler : any;
  13. private _sceneInstrumentation: BABYLON.SceneInstrumentation;
  14. private _engineInstrumentation: BABYLON.EngineInstrumentation;
  15. constructor(tabbar:TabBar, insp:Inspector) {
  16. super(tabbar, 'Stats');
  17. this._inspector = insp;
  18. this._scene = this._inspector.scene;
  19. this._engine = this._scene.getEngine();
  20. this._glInfo = this._engine.getGlInfo();
  21. this._sceneInstrumentation = new BABYLON.SceneInstrumentation(this._scene);
  22. this._sceneInstrumentation.captureActiveMeshesEvaluationTime = true;
  23. this._sceneInstrumentation.captureRenderTargetsRenderTime = true;
  24. this._sceneInstrumentation.captureFrameTime = true;
  25. this._sceneInstrumentation.captureRenderTime = true;
  26. this._sceneInstrumentation.captureInterFrameTime = true;
  27. this._sceneInstrumentation.captureParticlesRenderTime = true;
  28. this._sceneInstrumentation.captureSpritesRenderTime = true;
  29. this._engineInstrumentation = new BABYLON.EngineInstrumentation(this._engine);
  30. this._engineInstrumentation.captureGPUFrameTime = true;
  31. // Build the stats panel: a div that will contains all stats
  32. this._panel = Helpers.CreateDiv('tab-panel') as HTMLDivElement;
  33. this._panel.classList.add("stats-panel")
  34. let title = Helpers.CreateDiv('stat-title1', this._panel);
  35. let fpsSpan = Helpers.CreateElement('span', 'stats-fps');
  36. this._updatableProperties.push({
  37. elem:fpsSpan,
  38. updateFct:() => { return BABYLON.Tools.Format(this._inspector.scene.getEngine().getFps(), 0) + " fps"}
  39. });
  40. let versionSpan = Helpers.CreateElement('span');
  41. versionSpan.textContent = `Babylon.js v${BABYLON.Engine.Version} - `;
  42. title.appendChild(versionSpan);
  43. title.appendChild(fpsSpan);
  44. this._updateLoopHandler = this._update.bind(this);
  45. // Count block
  46. title = Helpers.CreateDiv('stat-title2', this._panel);
  47. title.textContent = "Count";
  48. {
  49. let elemLabel = this._createStatLabel("Total meshes", this._panel);
  50. let elemValue = Helpers.CreateDiv('stat-value', this._panel);
  51. this._updatableProperties.push({
  52. elem:elemValue,
  53. updateFct:() => { return this._scene.meshes.length.toString()}
  54. });
  55. elemLabel = this._createStatLabel("Draw calls", this._panel);
  56. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  57. this._updatableProperties.push({
  58. elem:elemValue,
  59. updateFct:() => { return this._sceneInstrumentation.drawCallsCounter.current.toString()}
  60. });
  61. elemLabel = this._createStatLabel("Total lights", this._panel);
  62. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  63. this._updatableProperties.push({
  64. elem:elemValue,
  65. updateFct:() => { return this._scene.lights.length.toString()}
  66. });
  67. elemLabel = this._createStatLabel("Total vertices", this._panel);
  68. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  69. this._updatableProperties.push({
  70. elem:elemValue,
  71. updateFct:() => { return this._scene.getTotalVertices().toString()}
  72. });
  73. elemLabel = this._createStatLabel("Total materials", this._panel);
  74. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  75. this._updatableProperties.push({
  76. elem:elemValue,
  77. updateFct:() => { return this._scene.materials.length.toString()}
  78. });
  79. elemLabel = this._createStatLabel("Total textures", this._panel);
  80. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  81. this._updatableProperties.push({
  82. elem:elemValue,
  83. updateFct:() => { return this._scene.textures.length.toString()}
  84. });
  85. elemLabel = this._createStatLabel("Active meshes", this._panel);
  86. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  87. this._updatableProperties.push({
  88. elem:elemValue,
  89. updateFct:() => { return this._scene.getActiveMeshes().length.toString()}
  90. });
  91. elemLabel = this._createStatLabel("Active indices", this._panel);
  92. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  93. this._updatableProperties.push({
  94. elem:elemValue,
  95. updateFct:() => { return this._scene.getActiveIndices().toString()}
  96. });
  97. elemLabel = this._createStatLabel("Active bones", this._panel);
  98. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  99. this._updatableProperties.push({
  100. elem:elemValue,
  101. updateFct:() => { return this._scene.getActiveBones().toString()}
  102. });
  103. elemLabel = this._createStatLabel("Active particles", this._panel);
  104. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  105. this._updatableProperties.push({
  106. elem:elemValue,
  107. updateFct:() => { return this._scene.getActiveParticles().toString()}
  108. });
  109. }
  110. title = Helpers.CreateDiv('stat-title2', this._panel);
  111. title.textContent = "Duration";
  112. {
  113. let elemLabel = this._createStatLabel("Meshes selection", this._panel);
  114. let elemValue = Helpers.CreateDiv('stat-value', this._panel);
  115. this._updatableProperties.push({
  116. elem:elemValue,
  117. updateFct:() => { return BABYLON.Tools.Format(this._sceneInstrumentation.activeMeshesEvaluationTimeCounter.current)}
  118. });
  119. elemLabel = this._createStatLabel("Render targets", this._panel);
  120. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  121. this._updatableProperties.push({
  122. elem:elemValue,
  123. updateFct:() => { return BABYLON.Tools.Format(this._sceneInstrumentation.renderTargetsRenderTimeCounter.current)}
  124. });
  125. elemLabel = this._createStatLabel("Particles", this._panel);
  126. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  127. this._updatableProperties.push({
  128. elem:elemValue,
  129. updateFct:() => { return BABYLON.Tools.Format(this._sceneInstrumentation.particlesRenderTimeCounter.current)}
  130. });
  131. elemLabel = this._createStatLabel("Sprites", this._panel);
  132. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  133. this._updatableProperties.push({
  134. elem:elemValue,
  135. updateFct:() => { return BABYLON.Tools.Format(this._sceneInstrumentation.spritesRenderTimeCounter.current)}
  136. });
  137. elemLabel = this._createStatLabel("Render", this._panel);
  138. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  139. this._updatableProperties.push({
  140. elem:elemValue,
  141. updateFct:() => { return BABYLON.Tools.Format(this._sceneInstrumentation.renderTimeCounter.current)}
  142. });
  143. elemLabel = this._createStatLabel("Frame", this._panel);
  144. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  145. this._updatableProperties.push({
  146. elem:elemValue,
  147. updateFct:() => { return BABYLON.Tools.Format(this._sceneInstrumentation.frameTimeCounter.current)}
  148. });
  149. elemLabel = this._createStatLabel("Inter-frame", this._panel);
  150. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  151. this._updatableProperties.push({
  152. elem:elemValue,
  153. updateFct:() => { return BABYLON.Tools.Format(this._sceneInstrumentation.interFrameTimeCounter.current)}
  154. });
  155. elemLabel = this._createStatLabel("GPU Frame time", this._panel);
  156. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  157. this._updatableProperties.push({
  158. elem:elemValue,
  159. updateFct:() => { return BABYLON.Tools.Format(this._engineInstrumentation.gpuFrameTimeCounter.current * 0.000001)}
  160. });
  161. elemLabel = this._createStatLabel("GPU Frame time (average)", this._panel);
  162. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  163. this._updatableProperties.push({
  164. elem:elemValue,
  165. updateFct:() => { return BABYLON.Tools.Format(this._engineInstrumentation.gpuFrameTimeCounter.average * 0.000001)}
  166. });
  167. elemLabel = this._createStatLabel("Potential FPS", this._panel);
  168. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  169. this._updatableProperties.push({
  170. elem:elemValue,
  171. updateFct:() => { return BABYLON.Tools.Format(1000.0 / this._sceneInstrumentation.frameTimeCounter.current, 0)}
  172. });
  173. elemLabel = this._createStatLabel("Resolution", this._panel);
  174. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  175. this._updatableProperties.push({
  176. elem:elemValue,
  177. updateFct:() => { return this._engine.getRenderWidth() + "x" + this._engine.getRenderHeight()}
  178. });
  179. }
  180. title = Helpers.CreateDiv('stat-title2', this._panel);
  181. title.textContent = "Extensions";
  182. {
  183. let elemLabel = this._createStatLabel("Std derivatives", this._panel);
  184. let elemValue = Helpers.CreateDiv('stat-value', this._panel);
  185. this._updatableProperties.push({
  186. elem:elemValue,
  187. updateFct:() => { return (this._engine.getCaps().standardDerivatives ? "Yes" : "No")}
  188. });
  189. elemLabel = this._createStatLabel("Compressed textures", this._panel);
  190. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  191. this._updatableProperties.push({
  192. elem:elemValue,
  193. updateFct:() => { return (this._engine.getCaps().s3tc ? "Yes" : "No")}
  194. });
  195. elemLabel = this._createStatLabel("Hardware instances", this._panel);
  196. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  197. this._updatableProperties.push({
  198. elem:elemValue,
  199. updateFct:() => { return (this._engine.getCaps().instancedArrays ? "Yes" : "No")}
  200. });
  201. elemLabel = this._createStatLabel("Texture float", this._panel);
  202. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  203. this._updatableProperties.push({
  204. elem:elemValue,
  205. updateFct:() => { return (this._engine.getCaps().textureFloat ? "Yes" : "No")}
  206. });
  207. elemLabel = this._createStatLabel("32bits indices", this._panel);
  208. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  209. this._updatableProperties.push({
  210. elem:elemValue,
  211. updateFct:() => { return (this._engine.getCaps().uintIndices ? "Yes" : "No")}
  212. });
  213. elemLabel = this._createStatLabel("Fragment depth", this._panel);
  214. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  215. this._updatableProperties.push({
  216. elem:elemValue,
  217. updateFct:() => { return (this._engine.getCaps().fragmentDepthSupported ? "Yes" : "No")}
  218. });
  219. elemLabel = this._createStatLabel("High precision shaders", this._panel);
  220. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  221. this._updatableProperties.push({
  222. elem:elemValue,
  223. updateFct:() => { return (this._engine.getCaps().highPrecisionShaderSupported ? "Yes" : "No")}
  224. });
  225. elemLabel = this._createStatLabel("Draw buffers", this._panel);
  226. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  227. this._updatableProperties.push({
  228. elem:elemValue,
  229. updateFct:() => { return (this._engine.getCaps().drawBuffersExtension ? "Yes" : "No")}
  230. });
  231. elemLabel = this._createStatLabel("Vertex array object", this._panel);
  232. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  233. this._updatableProperties.push({
  234. elem:elemValue,
  235. updateFct:() => { return (this._engine.getCaps().vertexArrayObject ? "Yes" : "No")}
  236. });
  237. elemLabel = this._createStatLabel("Timer query", this._panel);
  238. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  239. this._updatableProperties.push({
  240. elem:elemValue,
  241. updateFct:() => { return (this._engine.getCaps().timerQuery ? "Yes" : "No")}
  242. });
  243. }
  244. title = Helpers.CreateDiv('stat-title2', this._panel);
  245. title.textContent = "Caps.";
  246. {
  247. let elemLabel = this._createStatLabel("Stencil", this._panel);
  248. let elemValue = Helpers.CreateDiv('stat-value', this._panel);
  249. this._updatableProperties.push({
  250. elem:elemValue,
  251. updateFct:() => { return (this._engine.isStencilEnable ? "Enabled" : "Disabled")}
  252. });
  253. elemLabel = this._createStatLabel("Max textures units", this._panel);
  254. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  255. this._updatableProperties.push({
  256. elem:elemValue,
  257. updateFct:() => { return this._engine.getCaps().maxTexturesImageUnits.toString()}
  258. });
  259. elemLabel = this._createStatLabel("Max textures size", this._panel);
  260. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  261. this._updatableProperties.push({
  262. elem:elemValue,
  263. updateFct:() => { return this._engine.getCaps().maxTextureSize.toString()}
  264. });
  265. elemLabel = this._createStatLabel("Max anisotropy", this._panel);
  266. elemValue = Helpers.CreateDiv('stat-value', this._panel);
  267. this._updatableProperties.push({
  268. elem:elemValue,
  269. updateFct:() => { return this._engine.getCaps().maxAnisotropy.toString()}
  270. });
  271. }
  272. title = Helpers.CreateDiv('stat-title2', this._panel);
  273. title.textContent = "Info";
  274. {
  275. let elemValue = Helpers.CreateDiv('stat-infos', this._panel);
  276. this._updatableProperties.push({
  277. elem:elemValue,
  278. updateFct:() => { return "WebGL v" + this._engine.webGLVersion + " - " + this._glInfo.version + " - "+this._glInfo.renderer}
  279. });
  280. }
  281. }
  282. private _createStatLabel(content:string, parent: HTMLElement) : HTMLElement {
  283. let elem = Helpers.CreateDiv('stat-label', parent);
  284. elem.textContent = content;
  285. return elem;
  286. }
  287. /** Update each properties of the stats panel */
  288. private _update() {
  289. for (let prop of this._updatableProperties) {
  290. prop.elem.textContent = prop.updateFct();
  291. }
  292. }
  293. public dispose() {
  294. this._scene.unregisterAfterRender(this._updateLoopHandler);
  295. this._sceneInstrumentation.dispose();
  296. }
  297. public active(b: boolean){
  298. super.active(b);
  299. if(b){
  300. this._scene.registerAfterRender(this._updateLoopHandler);
  301. }
  302. }
  303. }
  304. }