dx8indexbuffer.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : ww3d *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/dx8indexbuffer.cpp $*
  25. * *
  26. * Original Author:: Jani Penttinen *
  27. * *
  28. * $Author:: Jani_p $*
  29. * *
  30. * $Modtime:: 11/09/01 3:12p $*
  31. * *
  32. * $Revision:: 26 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. //#define INDEX_BUFFER_LOG
  38. #include "dx8indexbuffer.h"
  39. #include "dx8wrapper.h"
  40. #include "dx8caps.h"
  41. #include "sphere.h"
  42. #include "thread.h"
  43. #include "wwmemlog.h"
  44. #define DEFAULT_IB_SIZE 5000
  45. static bool _DynamicSortingIndexArrayInUse=false;
  46. static SortingIndexBufferClass* _DynamicSortingIndexArray;
  47. static unsigned short _DynamicSortingIndexArraySize=0;
  48. static unsigned short _DynamicSortingIndexArrayOffset=0;
  49. static bool _DynamicDX8IndexBufferInUse=false;
  50. static DX8IndexBufferClass* _DynamicDX8IndexBuffer=NULL;
  51. static unsigned short _DynamicDX8IndexBufferSize=DEFAULT_IB_SIZE;
  52. static unsigned short _DynamicDX8IndexBufferOffset=0;
  53. static int _IndexBufferCount;
  54. static int _IndexBufferTotalIndices;
  55. static int _IndexBufferTotalSize;
  56. // ----------------------------------------------------------------------------
  57. //
  58. //
  59. //
  60. // ----------------------------------------------------------------------------
  61. IndexBufferClass::IndexBufferClass(unsigned type_, unsigned short index_count_)
  62. :
  63. index_count(index_count_),
  64. type(type_),
  65. engine_refs(0)
  66. {
  67. WWASSERT(type==BUFFER_TYPE_DX8 || type==BUFFER_TYPE_SORTING);
  68. WWASSERT(index_count);
  69. _IndexBufferCount++;
  70. _IndexBufferTotalIndices+=index_count;
  71. _IndexBufferTotalSize+=index_count*sizeof(unsigned short);
  72. #ifdef VERTEX_BUFFER_LOG
  73. WWDEBUG_SAY(("New IB, %d indices, size %d bytes\n",index_count,index_count*sizeof(unsigned short)));
  74. WWDEBUG_SAY(("Total IB count: %d, total %d indices, total size %d bytes\n",
  75. _IndexBufferCount,
  76. _IndexBufferTotalIndices,
  77. _IndexBufferTotalSize));
  78. #endif
  79. }
  80. IndexBufferClass::~IndexBufferClass()
  81. {
  82. _IndexBufferCount--;
  83. _IndexBufferTotalIndices-=index_count;
  84. _IndexBufferTotalSize-=index_count*sizeof(unsigned short);
  85. #ifdef VERTEX_BUFFER_LOG
  86. WWDEBUG_SAY(("Delete IB, %d indices, size %d bytes\n",index_count,index_count*sizeof(unsigned short)));
  87. WWDEBUG_SAY(("Total IB count: %d, total %d indices, total size %d bytes\n",
  88. _IndexBufferCount,
  89. _IndexBufferTotalIndices,
  90. _IndexBufferTotalSize));
  91. #endif
  92. }
  93. unsigned IndexBufferClass::Get_Total_Buffer_Count()
  94. {
  95. return _IndexBufferCount;
  96. }
  97. unsigned IndexBufferClass::Get_Total_Allocated_Indices()
  98. {
  99. return _IndexBufferTotalIndices;
  100. }
  101. unsigned IndexBufferClass::Get_Total_Allocated_Memory()
  102. {
  103. return _IndexBufferTotalSize;
  104. }
  105. void IndexBufferClass::Add_Engine_Ref() const
  106. {
  107. engine_refs++;
  108. }
  109. void IndexBufferClass::Release_Engine_Ref() const
  110. {
  111. engine_refs--;
  112. WWASSERT(engine_refs>=0);
  113. }
  114. // ----------------------------------------------------------------------------
  115. //
  116. //
  117. //
  118. // ----------------------------------------------------------------------------
  119. void IndexBufferClass::Copy(unsigned int* indices,unsigned first_index,unsigned count)
  120. {
  121. WWASSERT(indices);
  122. if (first_index) {
  123. DX8IndexBufferClass::AppendLockClass l(this,first_index,count);
  124. unsigned short* inds=l.Get_Index_Array();
  125. for (unsigned v=0;v<count;++v) {
  126. *inds++=unsigned short(*indices++);
  127. }
  128. }
  129. else {
  130. DX8IndexBufferClass::WriteLockClass l(this);
  131. unsigned short* inds=l.Get_Index_Array();
  132. for (unsigned v=0;v<count;++v) {
  133. *inds++=unsigned short(*indices++);
  134. }
  135. }
  136. }
  137. // ----------------------------------------------------------------------------
  138. void IndexBufferClass::Copy(unsigned short* indices,unsigned first_index,unsigned count)
  139. {
  140. WWASSERT(indices);
  141. if (first_index) {
  142. DX8IndexBufferClass::AppendLockClass l(this,first_index,count);
  143. unsigned short* inds=l.Get_Index_Array();
  144. for (unsigned v=0;v<count;++v) {
  145. *inds++=*indices++;
  146. }
  147. }
  148. else {
  149. DX8IndexBufferClass::WriteLockClass l(this);
  150. unsigned short* inds=l.Get_Index_Array();
  151. for (unsigned v=0;v<count;++v) {
  152. *inds++=*indices++;
  153. }
  154. }
  155. }
  156. // ----------------------------------------------------------------------------
  157. //
  158. //
  159. // ----------------------------------------------------------------------------
  160. IndexBufferClass::WriteLockClass::WriteLockClass(IndexBufferClass* index_buffer_, int flags) : index_buffer(index_buffer_)
  161. {
  162. DX8_THREAD_ASSERT();
  163. WWASSERT(index_buffer);
  164. WWASSERT(!index_buffer->Engine_Refs());
  165. index_buffer->Add_Ref();
  166. switch (index_buffer->Type()) {
  167. case BUFFER_TYPE_DX8:
  168. DX8_Assert();
  169. DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(index_buffer)->Get_DX8_Index_Buffer()->Lock(
  170. 0,
  171. index_buffer->Get_Index_Count()*sizeof(WORD),
  172. (unsigned char**)&indices,
  173. flags));
  174. break;
  175. case BUFFER_TYPE_SORTING:
  176. indices=static_cast<SortingIndexBufferClass*>(index_buffer)->index_buffer;
  177. break;
  178. default:
  179. WWASSERT(0);
  180. break;
  181. }
  182. }
  183. // ----------------------------------------------------------------------------
  184. //
  185. //
  186. // ----------------------------------------------------------------------------
  187. IndexBufferClass::WriteLockClass::~WriteLockClass()
  188. {
  189. DX8_THREAD_ASSERT();
  190. switch (index_buffer->Type()) {
  191. case BUFFER_TYPE_DX8:
  192. DX8_Assert();
  193. DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(index_buffer)->index_buffer->Unlock());
  194. break;
  195. case BUFFER_TYPE_SORTING:
  196. break;
  197. default:
  198. WWASSERT(0);
  199. break;
  200. }
  201. index_buffer->Release_Ref();
  202. }
  203. // ----------------------------------------------------------------------------
  204. IndexBufferClass::AppendLockClass::AppendLockClass(IndexBufferClass* index_buffer_,unsigned start_index, unsigned index_range)
  205. :
  206. index_buffer(index_buffer_)
  207. {
  208. DX8_THREAD_ASSERT();
  209. WWASSERT(start_index+index_range<=index_buffer->Get_Index_Count());
  210. WWASSERT(index_buffer);
  211. WWASSERT(!index_buffer->Engine_Refs());
  212. index_buffer->Add_Ref();
  213. switch (index_buffer->Type()) {
  214. case BUFFER_TYPE_DX8:
  215. DX8_Assert();
  216. DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(index_buffer)->index_buffer->Lock(
  217. start_index*sizeof(unsigned short),
  218. index_range*sizeof(unsigned short),
  219. (unsigned char**)&indices,
  220. 0));
  221. break;
  222. case BUFFER_TYPE_SORTING:
  223. indices=static_cast<SortingIndexBufferClass*>(index_buffer)->index_buffer+start_index;
  224. break;
  225. default:
  226. WWASSERT(0);
  227. break;
  228. }
  229. }
  230. // ----------------------------------------------------------------------------
  231. IndexBufferClass::AppendLockClass::~AppendLockClass()
  232. {
  233. DX8_THREAD_ASSERT();
  234. switch (index_buffer->Type()) {
  235. case BUFFER_TYPE_DX8:
  236. DX8_Assert();
  237. DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(index_buffer)->index_buffer->Unlock());
  238. break;
  239. case BUFFER_TYPE_SORTING:
  240. break;
  241. default:
  242. WWASSERT(0);
  243. break;
  244. }
  245. index_buffer->Release_Ref();
  246. }
  247. // ----------------------------------------------------------------------------
  248. //
  249. //
  250. //
  251. // ----------------------------------------------------------------------------
  252. DX8IndexBufferClass::DX8IndexBufferClass(unsigned short index_count_,UsageType usage)
  253. :
  254. IndexBufferClass(BUFFER_TYPE_DX8,index_count_)
  255. {
  256. DX8_THREAD_ASSERT();
  257. WWASSERT(index_count);
  258. unsigned usage_flags=
  259. D3DUSAGE_WRITEONLY|
  260. ((usage&USAGE_DYNAMIC) ? D3DUSAGE_DYNAMIC : 0)|
  261. ((usage&USAGE_NPATCHES) ? D3DUSAGE_NPATCHES : 0)|
  262. ((usage&USAGE_SOFTWAREPROCESSING) ? D3DUSAGE_SOFTWAREPROCESSING : 0);
  263. if (!DX8Wrapper::Get_Current_Caps()->Support_TnL()) {
  264. usage_flags|=D3DUSAGE_SOFTWAREPROCESSING;
  265. }
  266. HRESULT ret=DX8Wrapper::_Get_D3D_Device8()->CreateIndexBuffer(
  267. sizeof(WORD)*index_count,
  268. usage_flags,
  269. D3DFMT_INDEX16,
  270. (usage&USAGE_DYNAMIC) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED,
  271. &index_buffer);
  272. if (SUCCEEDED(ret)) {
  273. return;
  274. }
  275. WWDEBUG_SAY(("Index buffer creation failed, trying to release assets...\n"));
  276. // Vertex buffer creation failed, so try releasing least used textures and flushing the mesh cache.
  277. // Free all textures that haven't been used in the last 5 seconds
  278. TextureClass::Invalidate_Old_Unused_Textures(5000);
  279. // Invalidate the mesh cache
  280. WW3D::_Invalidate_Mesh_Cache();
  281. // Try again...
  282. ret=DX8Wrapper::_Get_D3D_Device8()->CreateIndexBuffer(
  283. sizeof(WORD)*index_count,
  284. usage_flags,
  285. D3DFMT_INDEX16,
  286. (usage&USAGE_DYNAMIC) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED,
  287. &index_buffer);
  288. if (SUCCEEDED(ret)) {
  289. WWDEBUG_SAY(("...Index buffer creation succesful\n"));
  290. }
  291. // If it still fails it is fatal
  292. DX8_ErrorCode(ret);
  293. }
  294. // ----------------------------------------------------------------------------
  295. DX8IndexBufferClass::~DX8IndexBufferClass()
  296. {
  297. index_buffer->Release();
  298. }
  299. // ----------------------------------------------------------------------------
  300. //
  301. //
  302. //
  303. // ----------------------------------------------------------------------------
  304. SortingIndexBufferClass::SortingIndexBufferClass(unsigned short index_count_)
  305. :
  306. IndexBufferClass(BUFFER_TYPE_SORTING,index_count_)
  307. {
  308. WWMEMLOG(MEM_RENDERER);
  309. WWASSERT(index_count);
  310. index_buffer=W3DNEWARRAY unsigned short[index_count];
  311. }
  312. // ----------------------------------------------------------------------------
  313. SortingIndexBufferClass::~SortingIndexBufferClass()
  314. {
  315. delete[] index_buffer;
  316. }
  317. // ----------------------------------------------------------------------------
  318. //
  319. //
  320. //
  321. // ----------------------------------------------------------------------------
  322. DynamicIBAccessClass::DynamicIBAccessClass(unsigned short type_, unsigned short index_count_)
  323. :
  324. IndexCount(index_count_),
  325. IndexBuffer(0),
  326. Type(type_)
  327. {
  328. WWASSERT(Type==BUFFER_TYPE_DYNAMIC_DX8 || Type==BUFFER_TYPE_DYNAMIC_SORTING);
  329. if (Type==BUFFER_TYPE_DYNAMIC_DX8) {
  330. Allocate_DX8_Dynamic_Buffer();
  331. }
  332. else {
  333. Allocate_Sorting_Dynamic_Buffer();
  334. }
  335. }
  336. DynamicIBAccessClass::~DynamicIBAccessClass()
  337. {
  338. REF_PTR_RELEASE(IndexBuffer);
  339. if (Type==BUFFER_TYPE_DYNAMIC_DX8) {
  340. _DynamicDX8IndexBufferInUse=false;
  341. _DynamicDX8IndexBufferOffset+=IndexCount;
  342. }
  343. else {
  344. _DynamicSortingIndexArrayInUse=false;
  345. _DynamicSortingIndexArrayOffset+=IndexCount;
  346. }
  347. }
  348. void DynamicIBAccessClass::_Deinit()
  349. {
  350. WWASSERT ((_DynamicDX8IndexBuffer == NULL) || (_DynamicDX8IndexBuffer->Num_Refs() == 1));
  351. REF_PTR_RELEASE(_DynamicDX8IndexBuffer);
  352. _DynamicDX8IndexBufferInUse=false;
  353. _DynamicDX8IndexBufferSize=DEFAULT_IB_SIZE;
  354. _DynamicDX8IndexBufferOffset=0;
  355. WWASSERT ((_DynamicSortingIndexArray == NULL) || (_DynamicSortingIndexArray->Num_Refs() == 1));
  356. REF_PTR_RELEASE(_DynamicSortingIndexArray);
  357. _DynamicSortingIndexArrayInUse=false;
  358. _DynamicSortingIndexArraySize=0;
  359. _DynamicSortingIndexArrayOffset=0;
  360. }
  361. // ----------------------------------------------------------------------------
  362. //
  363. //
  364. //
  365. // ----------------------------------------------------------------------------
  366. DynamicIBAccessClass::WriteLockClass::WriteLockClass(DynamicIBAccessClass* ib_access_)
  367. :
  368. DynamicIBAccess(ib_access_)
  369. {
  370. DX8_THREAD_ASSERT();
  371. DynamicIBAccess->IndexBuffer->Add_Ref();
  372. switch (DynamicIBAccess->Get_Type()) {
  373. case BUFFER_TYPE_DYNAMIC_DX8:
  374. WWASSERT(DynamicIBAccess);
  375. // WWASSERT(!dynamic_dx8_index_buffer->Engine_Refs());
  376. DX8_Assert();
  377. DX8_ErrorCode(
  378. static_cast<DX8IndexBufferClass*>(DynamicIBAccess->IndexBuffer)->Get_DX8_Index_Buffer()->Lock(
  379. DynamicIBAccess->IndexBufferOffset*sizeof(WORD),
  380. DynamicIBAccess->Get_Index_Count()*sizeof(WORD),
  381. (unsigned char**)&Indices,
  382. !DynamicIBAccess->IndexBufferOffset ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE));
  383. break;
  384. case BUFFER_TYPE_DYNAMIC_SORTING:
  385. Indices=static_cast<SortingIndexBufferClass*>(DynamicIBAccess->IndexBuffer)->index_buffer;
  386. Indices+=DynamicIBAccess->IndexBufferOffset;
  387. break;
  388. default:
  389. WWASSERT(0);
  390. break;
  391. }
  392. }
  393. DynamicIBAccessClass::WriteLockClass::~WriteLockClass()
  394. {
  395. DX8_THREAD_ASSERT();
  396. switch (DynamicIBAccess->Get_Type()) {
  397. case BUFFER_TYPE_DYNAMIC_DX8:
  398. DX8_Assert();
  399. DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(DynamicIBAccess->IndexBuffer)->Get_DX8_Index_Buffer()->Unlock());
  400. break;
  401. case BUFFER_TYPE_DYNAMIC_SORTING:
  402. break;
  403. default:
  404. WWASSERT(0);
  405. break;
  406. }
  407. DynamicIBAccess->IndexBuffer->Release_Ref();
  408. }
  409. // ----------------------------------------------------------------------------
  410. //
  411. //
  412. //
  413. // ----------------------------------------------------------------------------
  414. void DynamicIBAccessClass::Allocate_DX8_Dynamic_Buffer()
  415. {
  416. WWMEMLOG(MEM_RENDERER);
  417. WWASSERT(!_DynamicDX8IndexBufferInUse);
  418. _DynamicDX8IndexBufferInUse=true;
  419. // If requesting more indices than dynamic index buffer can fit, delete the ib
  420. // and adjust the size to the new count.
  421. if (IndexCount>_DynamicDX8IndexBufferSize) {
  422. REF_PTR_RELEASE(_DynamicDX8IndexBuffer);
  423. _DynamicDX8IndexBufferSize=IndexCount;
  424. if (_DynamicDX8IndexBufferSize<DEFAULT_IB_SIZE) _DynamicDX8IndexBufferSize=DEFAULT_IB_SIZE;
  425. }
  426. // Create a new vb if one doesn't exist currently
  427. if (!_DynamicDX8IndexBuffer) {
  428. unsigned usage=DX8IndexBufferClass::USAGE_DYNAMIC;
  429. if (DX8Wrapper::Get_Current_Caps()->Support_NPatches()) {
  430. usage|=DX8IndexBufferClass::USAGE_NPATCHES;
  431. }
  432. _DynamicDX8IndexBuffer=NEW_REF(DX8IndexBufferClass,(
  433. _DynamicDX8IndexBufferSize,
  434. (DX8IndexBufferClass::UsageType)usage));
  435. _DynamicDX8IndexBufferOffset=0;
  436. }
  437. // Any room at the end of the buffer?
  438. if (((unsigned)IndexCount+_DynamicDX8IndexBufferOffset)>_DynamicDX8IndexBufferSize) {
  439. _DynamicDX8IndexBufferOffset=0;
  440. }
  441. REF_PTR_SET(IndexBuffer,_DynamicDX8IndexBuffer);
  442. IndexBufferOffset=_DynamicDX8IndexBufferOffset;
  443. }
  444. void DynamicIBAccessClass::Allocate_Sorting_Dynamic_Buffer()
  445. {
  446. WWMEMLOG(MEM_RENDERER);
  447. WWASSERT(!_DynamicSortingIndexArrayInUse);
  448. _DynamicSortingIndexArrayInUse=true;
  449. unsigned new_index_count=_DynamicSortingIndexArrayOffset+IndexCount;
  450. WWASSERT(new_index_count<65536);
  451. if (new_index_count>_DynamicSortingIndexArraySize) {
  452. REF_PTR_RELEASE(_DynamicSortingIndexArray);
  453. _DynamicSortingIndexArraySize=new_index_count;
  454. if (_DynamicSortingIndexArraySize<DEFAULT_IB_SIZE) _DynamicSortingIndexArraySize=DEFAULT_IB_SIZE;
  455. }
  456. if (!_DynamicSortingIndexArray) {
  457. _DynamicSortingIndexArray=NEW_REF(SortingIndexBufferClass,(_DynamicSortingIndexArraySize));
  458. _DynamicSortingIndexArrayOffset=0;
  459. }
  460. REF_PTR_SET(IndexBuffer,_DynamicSortingIndexArray);
  461. IndexBufferOffset=_DynamicSortingIndexArrayOffset;
  462. }
  463. void DynamicIBAccessClass::_Reset(bool frame_changed)
  464. {
  465. _DynamicSortingIndexArrayOffset=0;
  466. if (frame_changed) _DynamicDX8IndexBufferOffset=0;
  467. }
  468. unsigned short DynamicIBAccessClass::Get_Default_Index_Count(void)
  469. {
  470. return _DynamicDX8IndexBufferSize;
  471. }
  472. /*Added so that VisualC++ doesn't remove our try/catch blocks around index buffer access.
  473. This is needed because of a Windows 2000 Kernal bug as explained in the DX 9.0b readme file.*/
  474. int IndexBufferExceptionFunc(void)
  475. {
  476. int b=1;
  477. b += _IndexBufferTotalIndices;
  478. return b;
  479. }