statistics.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "statistics.h"
  19. #include "wwstring.h"
  20. #include "simplevec.h"
  21. #include "dx8renderer.h"
  22. #include "dx8wrapper.h"
  23. #include "dx8caps.h"
  24. #include "textureloader.h"
  25. #include "texture.h"
  26. #include <cstdio>
  27. #include <memory.h>
  28. #ifdef _UNIX
  29. #include "osdep.h"
  30. #endif
  31. // ----------------------------------------------------------------------------
  32. //
  33. // Texture memory tracking system
  34. //
  35. // ----------------------------------------------------------------------------
  36. static int texture_memory;
  37. static int texture_count;
  38. static int lightmap_texture_memory;
  39. static int lightmap_texture_count;
  40. static int procedural_texture_memory;
  41. static int procedural_texture_count;
  42. static int record_count;
  43. static int texture_change_count;
  44. static int last_frame_texture_memory;
  45. static int last_frame_texture_count;
  46. static int last_frame_lightmap_texture_memory;
  47. static int last_frame_lightmap_texture_count;
  48. static int last_frame_procedural_texture_memory;
  49. static int last_frame_procedural_texture_count;
  50. static int last_frame_record_count;
  51. static int last_frame_texture_change_count;
  52. static TextureClass* latest_texture;
  53. static Debug_Statistics::RecordTextureMode record_texture_mode;
  54. static StringClass texture_statistics_string;
  55. struct TextureStatisticsStruct
  56. {
  57. TextureClass* tex;
  58. int usage_count;
  59. int change_count;
  60. };
  61. static SimpleDynVecClass<TextureStatisticsStruct> texture_statistics;
  62. static void Record_Texture_Begin()
  63. {
  64. texture_memory=0;
  65. texture_count=0;
  66. lightmap_texture_memory=0;
  67. lightmap_texture_count=0;
  68. procedural_texture_memory=0;
  69. procedural_texture_count=0;
  70. record_count=0;
  71. texture_change_count=0;
  72. latest_texture=NULL;
  73. texture_statistics.Resize(0);
  74. }
  75. static void Record_Texture_End()
  76. {
  77. last_frame_texture_memory=texture_memory;
  78. last_frame_texture_count=texture_count;
  79. last_frame_lightmap_texture_memory=lightmap_texture_memory;
  80. last_frame_lightmap_texture_count=lightmap_texture_count;
  81. last_frame_procedural_texture_memory=procedural_texture_memory;
  82. last_frame_procedural_texture_count=procedural_texture_count;
  83. last_frame_record_count=record_count;
  84. last_frame_texture_change_count=texture_change_count;
  85. texture_statistics_string="";
  86. if (record_texture_mode==Debug_Statistics::RECORD_TEXTURE_DETAILS) {
  87. char tmp_text[1024];
  88. _snprintf(tmp_text,sizeof(tmp_text),
  89. "Set_DX8_Texture count: %d\nactual changes: %d\n\n"
  90. "id refs changes size name\n"
  91. "--------------------------------------\n",
  92. last_frame_record_count,last_frame_texture_change_count);
  93. texture_statistics_string+=tmp_text;
  94. for (int a=0;a<texture_count;++a) {
  95. StringClass working_string;
  96. TextureClass* t=texture_statistics[a].tex;
  97. int id=0;
  98. StringClass flash=" ";
  99. // if (t && t->getClassID() == ID_TEXTURE_FILE_CLASS) {
  100. // TextureFileClass* tfc=static_cast<TextureFileClass*>(t);
  101. // id=tfc->ID();
  102. // if (tfc->Get_Texture_Flash()) flash="F";
  103. // }
  104. working_string.Format("%4.4d %3.3d %3.3d %s ",id,texture_statistics[a].usage_count,texture_statistics[a].change_count,flash.Peek_Buffer());
  105. texture_statistics_string+=working_string;
  106. StringClass error="";
  107. if (t) {
  108. // int red_factor=t->Get_Current_Reduction_Factor();
  109. unsigned bytes=t->Get_Texture_Memory_Usage();
  110. // unsigned non_red_bytes=t->Get_Non_Reduced_Texture_Memory_Usage();
  111. if (!t->Is_Initialized()) {
  112. // non_red_bytes=bytes;
  113. texture_statistics_string+="*";
  114. }
  115. else {
  116. texture_statistics_string+=" ";
  117. }
  118. // if (!non_red_bytes) non_red_bytes=1;
  119. // int percents=100-100*bytes/non_red_bytes;
  120. working_string.Format("%4.4dkb ",bytes/1024);
  121. texture_statistics_string+=working_string;
  122. }
  123. else {
  124. texture_statistics_string+="N/A ";
  125. }
  126. texture_statistics_string+=t->Get_Texture_Name();//getTextureName();
  127. texture_statistics_string+=error;
  128. texture_statistics_string+="\n";
  129. }
  130. texture_statistics_string+="\nid = id of texture. Use with command 'flash_texture [id]'\n";
  131. texture_statistics_string+="refs = # of times texture is used when rendering\n";
  132. texture_statistics_string+="changes = # of times texture change needed - BAD IF HIGH!\n";
  133. texture_statistics_string+="red = texture reduction factor\n";
  134. texture_statistics_string+="size = amount of memory needed for texture\n";
  135. texture_statistics_string+="(w/o red) = size of reduction not used\n";
  136. texture_statistics_string+="percent = savings of reduction system, in percents\n";
  137. texture_statistics_string+="\n* = thumbnail used\n";
  138. texture_statistics_string+="\n";
  139. // texture_statistics_string+=TextureFileClass::List_Missing_Files();
  140. }
  141. }
  142. void Debug_Statistics::Record_Texture_Mode(RecordTextureMode mode)
  143. {
  144. record_texture_mode=mode;
  145. }
  146. Debug_Statistics::RecordTextureMode Debug_Statistics::Get_Record_Texture_Mode()
  147. {
  148. return record_texture_mode;
  149. }
  150. static bool Find_Record_Texture(TextureClass* t)
  151. {
  152. for (int a=0;a<texture_count;++a) {
  153. if (texture_statistics[a].tex==t) {
  154. if (record_texture_mode==Debug_Statistics::RECORD_TEXTURE_DETAILS) {
  155. texture_statistics[a].usage_count++;
  156. if (t!=latest_texture) {
  157. texture_statistics[a].change_count++;
  158. }
  159. }
  160. return true;
  161. }
  162. }
  163. return false;
  164. }
  165. static void Add_Record_Texture(TextureClass* t)
  166. {
  167. TextureStatisticsStruct tss;
  168. tss.tex=t;
  169. tss.usage_count=1;
  170. tss.change_count=1;
  171. texture_statistics.Add(tss);
  172. texture_count++;
  173. if (t->Is_Lightmap()) lightmap_texture_count++;
  174. if (t->Is_Procedural()) procedural_texture_count++;
  175. }
  176. void Debug_Statistics::Record_Texture(TextureClass* t)
  177. {
  178. record_count++;
  179. if (t!=latest_texture) {
  180. texture_change_count++;
  181. }
  182. if (record_texture_mode==RECORD_TEXTURE_NONE) {
  183. latest_texture=t;
  184. return;
  185. }
  186. if (!t) {
  187. latest_texture=t;
  188. return;
  189. }
  190. if (Find_Record_Texture(t)) {
  191. latest_texture=t;
  192. return;
  193. }
  194. Add_Record_Texture(t);
  195. texture_memory+=t->Get_Texture_Memory_Usage();
  196. latest_texture=t;
  197. if (t->Is_Lightmap()) lightmap_texture_memory+=t->Get_Texture_Memory_Usage();
  198. if (t->Is_Procedural()) procedural_texture_memory+=t->Get_Texture_Memory_Usage();
  199. }
  200. int Debug_Statistics::Get_Record_Texture_Size() // Return total textures used during latest frame, in bytes
  201. {
  202. return last_frame_texture_memory;
  203. }
  204. int Debug_Statistics::Get_Record_Texture_Count() // Return total textures used during latest frame, in bytes
  205. {
  206. return last_frame_texture_count;
  207. }
  208. int Debug_Statistics::Get_Record_Texture_Change_Count()
  209. {
  210. return last_frame_texture_change_count;
  211. }
  212. int Debug_Statistics::Get_Record_Lightmap_Texture_Size() // Return total lightmap textures used during latest frame, in bytes
  213. {
  214. return last_frame_lightmap_texture_memory;
  215. }
  216. int Debug_Statistics::Get_Record_Lightmap_Texture_Count() // Return total lightmap textures used during latest frame, in bytes
  217. {
  218. return last_frame_lightmap_texture_count;
  219. }
  220. int Debug_Statistics::Get_Record_Procedural_Texture_Size() // Return total procedural textures used during latest frame, in bytes
  221. {
  222. return last_frame_procedural_texture_memory;
  223. }
  224. int Debug_Statistics::Get_Record_Procedural_Texture_Count() // Return total procedural textures used during latest frame, in bytes
  225. {
  226. return last_frame_procedural_texture_count;
  227. }
  228. const StringClass& Debug_Statistics::Get_Record_Texture_String()
  229. {
  230. return texture_statistics_string;
  231. }
  232. // ----------------------------------------------------------------------------
  233. static int dx8_skin_renders;
  234. static int last_frame_dx8_skin_renders;
  235. static int dx8_skin_polygons;
  236. static int last_frame_dx8_skin_polygons;
  237. static int dx8_skin_vertices;
  238. static int last_frame_dx8_skin_vertices;
  239. static int dx8_polygons;
  240. static int last_frame_dx8_polygons;
  241. static int dx8_vertices;
  242. static int last_frame_dx8_vertices;
  243. static int sorting_polygons;
  244. static int last_frame_sorting_polygons;
  245. static int sorting_vertices;
  246. static int last_frame_sorting_vertices;
  247. static int draw_calls;
  248. static int last_frame_draw_calls;
  249. void Debug_Statistics::Record_DX8_Skin_Polys_And_Vertices(int pcount,int vcount)
  250. {
  251. dx8_skin_polygons+=pcount;
  252. dx8_skin_vertices+=vcount;
  253. dx8_skin_renders++;
  254. draw_calls++;
  255. }
  256. void Debug_Statistics::Record_DX8_Polys_And_Vertices(int pcount,int vcount,const ShaderClass& shader)
  257. {
  258. if (shader.Get_NPatch_Enable()==ShaderClass::NPATCH_ENABLE && DX8Caps::Support_NPatches()) {
  259. unsigned level=WW3D::Get_NPatches_Level();
  260. level*=level;
  261. pcount*=level;
  262. }
  263. dx8_polygons+=pcount;
  264. dx8_vertices+=vcount;
  265. draw_calls++;
  266. }
  267. int Debug_Statistics::Get_DX8_Skin_Renders()
  268. {
  269. return last_frame_dx8_skin_renders;
  270. }
  271. int Debug_Statistics::Get_DX8_Skin_Polygons()
  272. {
  273. return last_frame_dx8_skin_polygons;
  274. }
  275. int Debug_Statistics::Get_DX8_Skin_Vertices()
  276. {
  277. return last_frame_dx8_skin_vertices;
  278. }
  279. int Debug_Statistics::Get_DX8_Polygons()
  280. {
  281. return last_frame_dx8_polygons;
  282. }
  283. int Debug_Statistics::Get_DX8_Vertices()
  284. {
  285. return last_frame_dx8_vertices;
  286. }
  287. void Debug_Statistics::Record_Sorting_Polys_And_Vertices(int pcount,int vcount)
  288. {
  289. sorting_polygons+=pcount;
  290. sorting_vertices+=vcount;
  291. draw_calls++;
  292. }
  293. int Debug_Statistics::Get_Sorting_Polygons()
  294. {
  295. return last_frame_sorting_polygons;
  296. }
  297. int Debug_Statistics::Get_Sorting_Vertices()
  298. {
  299. return last_frame_sorting_vertices;
  300. }
  301. int Debug_Statistics::Get_Draw_Calls()
  302. {
  303. return last_frame_draw_calls;
  304. }
  305. // ----------------------------------------------------------------------------
  306. //
  307. //
  308. //
  309. // ----------------------------------------------------------------------------
  310. void Debug_Statistics::Begin_Statistics()
  311. {
  312. dx8_polygons=0;
  313. dx8_vertices=0;
  314. dx8_skin_polygons=0;
  315. dx8_skin_vertices=0;
  316. dx8_skin_renders=0;
  317. sorting_polygons=0;
  318. sorting_vertices=0;
  319. draw_calls=0;
  320. Record_Texture_Begin();
  321. DX8Wrapper::Begin_Statistics();
  322. // DX8MeshRendererClass::Begin_Statistics();
  323. }
  324. void Debug_Statistics::End_Statistics()
  325. {
  326. Record_Texture_End();
  327. last_frame_dx8_skin_polygons=dx8_skin_polygons;
  328. last_frame_dx8_skin_vertices=dx8_skin_vertices;
  329. last_frame_dx8_skin_renders=dx8_skin_renders;
  330. last_frame_dx8_polygons=dx8_polygons;
  331. last_frame_dx8_vertices=dx8_vertices;
  332. last_frame_sorting_polygons=sorting_polygons;
  333. last_frame_sorting_vertices=sorting_vertices;
  334. last_frame_draw_calls=draw_calls;
  335. // DX8MeshRendererClass::End_Statistics();
  336. DX8Wrapper::End_Statistics();
  337. }
  338. void Debug_Statistics::Shutdown_Statistics()
  339. {
  340. texture_statistics_string.Release_Resources();
  341. }
  342. // ----------------------------------------------------------------------------