W3DBufferManager.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. #include "Common/Debug.h"
  24. #include "W3DDevice/GameClient/W3DBufferManager.h"
  25. W3DBufferManager *TheW3DBufferManager=NULL; //singleton
  26. static int FVFTypeIndexList[W3DBufferManager::MAX_FVF]=
  27. {
  28. D3DFVF_XYZ,
  29. D3DFVF_XYZ|D3DFVF_DIFFUSE,
  30. D3DFVF_XYZ|D3DFVF_TEX1,
  31. D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1,
  32. D3DFVF_XYZ|D3DFVF_TEX2,
  33. D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX2,
  34. D3DFVF_XYZ|D3DFVF_NORMAL,
  35. D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE,
  36. D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
  37. D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1,
  38. D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2,
  39. D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX2,
  40. D3DFVF_XYZRHW,
  41. D3DFVF_XYZRHW|D3DFVF_DIFFUSE,
  42. D3DFVF_XYZRHW|D3DFVF_TEX1,
  43. D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1,
  44. D3DFVF_XYZRHW|D3DFVF_TEX2,
  45. D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX2
  46. };
  47. Int W3DBufferManager::getDX8Format(VBM_FVF_TYPES format)
  48. {
  49. return FVFTypeIndexList[format];
  50. }
  51. W3DBufferManager::W3DBufferManager(void)
  52. {
  53. m_numEmptySlotsAllocated=0;
  54. m_numEmptyVertexBuffersAllocated=0;
  55. m_numEmptyIndexSlotsAllocated=0;
  56. m_numEmptyIndexBuffersAllocated=0;
  57. for (Int i=0; i<MAX_FVF; i++)
  58. m_W3DVertexBuffers[i]=NULL;
  59. for (i=0; i<MAX_FVF; i++)
  60. for (Int j=0; j<MAX_VB_SIZES; j++)
  61. m_W3DVertexBufferSlots[i][j]=NULL;
  62. m_W3DIndexBuffers=NULL;
  63. for (Int j=0; j<MAX_IB_SIZES; j++)
  64. m_W3DIndexBufferSlots[j]=NULL;
  65. }
  66. W3DBufferManager::~W3DBufferManager(void)
  67. {
  68. freeAllSlots();
  69. freeAllBuffers();
  70. }
  71. void W3DBufferManager::freeAllSlots(void)
  72. {
  73. Int i,j;
  74. for (i=0; i<MAX_FVF; i++)
  75. {
  76. for (j=0; j<MAX_VB_SIZES; j++)
  77. {
  78. //Release all slots allocated for each size
  79. W3DVertexBufferSlot *vbSlot = m_W3DVertexBufferSlots[i][j];
  80. while (vbSlot)
  81. {
  82. if (vbSlot->m_prevSameVB)
  83. vbSlot->m_prevSameVB->m_nextSameVB=vbSlot->m_nextSameVB;
  84. else
  85. vbSlot->m_VB->m_usedSlots=NULL;
  86. if (vbSlot->m_nextSameVB)
  87. vbSlot->m_nextSameVB->m_prevSameVB=vbSlot->m_prevSameVB;
  88. vbSlot=vbSlot->m_nextSameSize;
  89. m_numEmptySlotsAllocated--;
  90. }
  91. m_W3DVertexBufferSlots[i][j]=NULL;
  92. }
  93. }
  94. for (j=0; j<MAX_IB_SIZES; j++)
  95. {
  96. //Release all slots allocated for each size
  97. W3DIndexBufferSlot *ibSlot = m_W3DIndexBufferSlots[j];
  98. while (ibSlot)
  99. {
  100. if (ibSlot->m_prevSameIB)
  101. ibSlot->m_prevSameIB->m_nextSameIB=ibSlot->m_nextSameIB;
  102. else
  103. ibSlot->m_IB->m_usedSlots=NULL;
  104. if (ibSlot->m_nextSameIB)
  105. ibSlot->m_nextSameIB->m_prevSameIB=ibSlot->m_prevSameIB;
  106. ibSlot=ibSlot->m_nextSameSize;
  107. m_numEmptyIndexSlotsAllocated--;
  108. }
  109. m_W3DIndexBufferSlots[j]=NULL;
  110. }
  111. DEBUG_ASSERTCRASH(m_numEmptySlotsAllocated==0, ("Failed to free all empty vertex buffer slots"));
  112. DEBUG_ASSERTCRASH(m_numEmptyIndexSlotsAllocated==0, ("Failed to free all empty index buffer slots"));
  113. }
  114. void W3DBufferManager::freeAllBuffers(void)
  115. {
  116. Int i;
  117. //Make sure all slots are free
  118. freeAllSlots(); ///<release all slots to pool.
  119. for (i=0; i<MAX_FVF; i++)
  120. {
  121. W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
  122. while (vb)
  123. { DEBUG_ASSERTCRASH(vb->m_usedSlots == NULL, ("Freeing Non-Empty Vertex Buffer"));
  124. REF_PTR_RELEASE(vb->m_DX8VertexBuffer);
  125. m_numEmptyVertexBuffersAllocated--;
  126. vb=vb->m_nextVB; //get next vertex buffer of this type
  127. }
  128. m_W3DVertexBuffers[i]=NULL;
  129. }
  130. W3DIndexBuffer *ib = m_W3DIndexBuffers;
  131. while (ib)
  132. { DEBUG_ASSERTCRASH(ib->m_usedSlots == NULL, ("Freeing Non-Empty Index Buffer"));
  133. REF_PTR_RELEASE(ib->m_DX8IndexBuffer);
  134. m_numEmptyIndexBuffersAllocated--;
  135. ib=ib->m_nextIB; //get next vertex buffer of this type
  136. }
  137. m_W3DIndexBuffers=NULL;
  138. DEBUG_ASSERTCRASH(m_numEmptyVertexBuffersAllocated==0, ("Failed to free all empty vertex buffers"));
  139. DEBUG_ASSERTCRASH(m_numEmptyIndexBuffersAllocated==0, ("Failed to free all empty index buffers"));
  140. }
  141. void W3DBufferManager::ReleaseResources(void)
  142. {
  143. for (Int i=0; i<MAX_FVF; i++)
  144. {
  145. W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
  146. while (vb)
  147. {
  148. REF_PTR_RELEASE(vb->m_DX8VertexBuffer);
  149. vb=vb->m_nextVB; //get next vertex buffer of this type
  150. }
  151. }
  152. W3DIndexBuffer *ib = m_W3DIndexBuffers;
  153. while (ib)
  154. {
  155. REF_PTR_RELEASE(ib->m_DX8IndexBuffer);
  156. ib=ib->m_nextIB; //get next vertex buffer of this type
  157. }
  158. }
  159. Bool W3DBufferManager::ReAcquireResources(void)
  160. {
  161. for (Int i=0; i<MAX_FVF; i++)
  162. {
  163. W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
  164. while (vb)
  165. { DEBUG_ASSERTCRASH( vb->m_DX8VertexBuffer == NULL, ("ReAcquire of existing vertex buffer"));
  166. vb->m_DX8VertexBuffer=NEW_REF(DX8VertexBufferClass,(FVFTypeIndexList[vb->m_format],vb->m_size,DX8VertexBufferClass::USAGE_DEFAULT));
  167. DEBUG_ASSERTCRASH( vb->m_DX8VertexBuffer, ("Failed ReAcquire of vertex buffer"));
  168. if (!vb->m_DX8VertexBuffer)
  169. return FALSE;
  170. vb=vb->m_nextVB; //get next vertex buffer of this type
  171. }
  172. }
  173. W3DIndexBuffer *ib = m_W3DIndexBuffers;
  174. while (ib)
  175. { DEBUG_ASSERTCRASH( ib->m_DX8IndexBuffer == NULL, ("ReAcquire of existing index buffer"));
  176. ib->m_DX8IndexBuffer=NEW_REF(DX8IndexBufferClass,(ib->m_size,DX8IndexBufferClass::USAGE_DEFAULT));
  177. DEBUG_ASSERTCRASH( ib->m_DX8IndexBuffer, ("Failed ReAcquire of index buffer"));
  178. if (!ib->m_DX8IndexBuffer)
  179. return FALSE;
  180. ib=ib->m_nextIB; //get next vertex buffer of this type
  181. }
  182. return TRUE;
  183. }
  184. /**Searches through previously allocated vertex buffer slots and returns a matching type. If none found,
  185. creates a new slot and adds it to the pool. Returns an integer slotId used to reference the VB.
  186. Returns -1 in case of failure.
  187. */
  188. W3DBufferManager::W3DVertexBufferSlot *W3DBufferManager::getSlot(VBM_FVF_TYPES fvfType, Int size)
  189. {
  190. W3DVertexBufferSlot *vbSlot=NULL;
  191. //round size to next multiple of minimum slot size.
  192. //should help avoid fragmentation.
  193. size = (size + (MIN_SLOT_SIZE-1)) & (~(MIN_SLOT_SIZE-1));
  194. Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
  195. DEBUG_ASSERTCRASH(sizeIndex < MAX_VB_SIZES && size, ("Allocating too large vertex buffer slot"));
  196. if ((vbSlot=m_W3DVertexBufferSlots[fvfType][sizeIndex]) != 0)
  197. { //found a previously allocated slot matching required size
  198. m_W3DVertexBufferSlots[fvfType][sizeIndex]=vbSlot->m_nextSameSize;
  199. if (vbSlot->m_nextSameSize)
  200. vbSlot->m_nextSameSize->m_prevSameSize=NULL;
  201. return vbSlot;
  202. }
  203. else
  204. { //need to allocate a new slot
  205. return allocateSlotStorage(fvfType, size);
  206. }
  207. return NULL;
  208. }
  209. /**Returns vertex buffer space back to pool so it can be reused later*/
  210. void W3DBufferManager::releaseSlot(W3DVertexBufferSlot *vbSlot)
  211. {
  212. Int sizeIndex = (vbSlot->m_size >> MIN_SLOT_SIZE_SHIFT)-1;
  213. vbSlot->m_nextSameSize=m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex];
  214. if (m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex])
  215. m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex]->m_prevSameSize=vbSlot;
  216. m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex]=vbSlot;
  217. }
  218. /**Reserves space inside existing vertex buffer or allocates a new one to fit the required size.
  219. */
  220. W3DBufferManager::W3DVertexBufferSlot * W3DBufferManager::allocateSlotStorage(VBM_FVF_TYPES fvfType, Int size)
  221. {
  222. W3DVertexBuffer *pVB;
  223. W3DVertexBufferSlot *vbSlot;
  224. // Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
  225. DEBUG_ASSERTCRASH(m_numEmptySlotsAllocated < MAX_NUMBER_SLOTS, ("Nore more VB Slots"));
  226. pVB=m_W3DVertexBuffers[fvfType];
  227. while (pVB)
  228. {
  229. if ((pVB->m_size - pVB->m_startFreeIndex) >= size)
  230. { //found enough free space in this vertex buffer
  231. if (m_numEmptySlotsAllocated < MAX_NUMBER_SLOTS)
  232. { //we're allowing more slots to be allocated.
  233. vbSlot=&m_W3DVertexBufferEmptySlots[m_numEmptySlotsAllocated];
  234. vbSlot->m_size=size;
  235. vbSlot->m_start=pVB->m_startFreeIndex;
  236. vbSlot->m_VB=pVB;
  237. //Link to VB list of slots
  238. vbSlot->m_nextSameVB=pVB->m_usedSlots;
  239. vbSlot->m_prevSameVB=NULL; //this will be the new head
  240. if (pVB->m_usedSlots)
  241. pVB->m_usedSlots->m_prevSameVB=vbSlot;
  242. vbSlot->m_prevSameSize=vbSlot->m_nextSameSize=NULL;
  243. pVB->m_usedSlots=vbSlot;
  244. pVB->m_startFreeIndex += size;
  245. m_numEmptySlotsAllocated++;
  246. return vbSlot;
  247. }
  248. }
  249. pVB = pVB->m_nextVB;
  250. }
  251. pVB=m_W3DVertexBuffers[fvfType]; //save old list head
  252. //Didn't find any vertex buffers with room, create a new one
  253. DEBUG_ASSERTCRASH(m_numEmptyVertexBuffersAllocated < MAX_VERTEX_BUFFERS_CREATED, ("Reached Max Static VB Shadow Geometry"));
  254. if (m_numEmptyVertexBuffersAllocated < MAX_VERTEX_BUFFERS_CREATED)
  255. {
  256. m_W3DVertexBuffers[fvfType] = &m_W3DEmptyVertexBuffers[m_numEmptyVertexBuffersAllocated];
  257. m_W3DVertexBuffers[fvfType]->m_nextVB=pVB; //link to list
  258. m_numEmptyVertexBuffersAllocated++;
  259. pVB=m_W3DVertexBuffers[fvfType]; //get new list head
  260. Int vbSize=__max(DEFAULT_VERTEX_BUFFER_SIZE,size);
  261. pVB->m_DX8VertexBuffer=NEW_REF(DX8VertexBufferClass,(FVFTypeIndexList[fvfType],vbSize,DX8VertexBufferClass::USAGE_DEFAULT));
  262. pVB->m_format=fvfType;
  263. pVB->m_startFreeIndex=size;
  264. pVB->m_size=vbSize;
  265. vbSlot=&m_W3DVertexBufferEmptySlots[m_numEmptySlotsAllocated];
  266. m_numEmptySlotsAllocated++;
  267. pVB->m_usedSlots=vbSlot;
  268. vbSlot->m_size=size;
  269. vbSlot->m_start=0;
  270. vbSlot->m_VB=pVB;
  271. vbSlot->m_prevSameVB=vbSlot->m_nextSameVB=NULL;
  272. vbSlot->m_prevSameSize=vbSlot->m_nextSameSize=NULL;
  273. return vbSlot;
  274. }
  275. return NULL;
  276. }
  277. //******************************** Index Buffer code ******************************************************
  278. /**Searches through previously allocated index buffer slots and returns a matching type. If none found,
  279. creates a new slot and adds it to the pool. Returns an integer slotId used to reference the VB.
  280. Returns -1 in case of failure.
  281. */
  282. W3DBufferManager::W3DIndexBufferSlot *W3DBufferManager::getSlot(Int size)
  283. {
  284. W3DIndexBufferSlot *ibSlot=NULL;
  285. //round size to next multiple of minimum slot size.
  286. //should help avoid fragmentation.
  287. size = (size + (MIN_SLOT_SIZE-1)) & (~(MIN_SLOT_SIZE-1));
  288. Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
  289. DEBUG_ASSERTCRASH(sizeIndex < MAX_IB_SIZES && size, ("Allocating too large index buffer slot"));
  290. if ((ibSlot=m_W3DIndexBufferSlots[sizeIndex]) != 0)
  291. { //found a previously allocated slot matching required size
  292. m_W3DIndexBufferSlots[sizeIndex]=ibSlot->m_nextSameSize;
  293. if (ibSlot->m_nextSameSize)
  294. ibSlot->m_nextSameSize->m_prevSameSize=NULL;
  295. return ibSlot;
  296. }
  297. else
  298. { //need to allocate a new slot
  299. return allocateSlotStorage(size);
  300. }
  301. return NULL;
  302. }
  303. /**Returns index buffer space back to pool so it can be reused later*/
  304. void W3DBufferManager::releaseSlot(W3DIndexBufferSlot *ibSlot)
  305. {
  306. Int sizeIndex = (ibSlot->m_size >> MIN_SLOT_SIZE_SHIFT)-1;
  307. ibSlot->m_nextSameSize=m_W3DIndexBufferSlots[sizeIndex];
  308. if (m_W3DIndexBufferSlots[sizeIndex])
  309. m_W3DIndexBufferSlots[sizeIndex]->m_prevSameSize=ibSlot;
  310. m_W3DIndexBufferSlots[sizeIndex]=ibSlot;
  311. }
  312. /**Reserves space inside existing index buffer or allocates a new one to fit the required size.
  313. */
  314. W3DBufferManager::W3DIndexBufferSlot * W3DBufferManager::allocateSlotStorage(Int size)
  315. {
  316. W3DIndexBuffer *pIB;
  317. W3DIndexBufferSlot *ibSlot;
  318. // Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
  319. DEBUG_ASSERTCRASH(m_numEmptyIndexSlotsAllocated < MAX_NUMBER_SLOTS, ("Nore more IB Slots"));
  320. pIB=m_W3DIndexBuffers;
  321. while (pIB)
  322. {
  323. if ((pIB->m_size - pIB->m_startFreeIndex) >= size)
  324. { //found enough free space in this index buffer
  325. if (m_numEmptyIndexSlotsAllocated < MAX_NUMBER_SLOTS)
  326. { //we're allowing more slots to be allocated.
  327. ibSlot=&m_W3DIndexBufferEmptySlots[m_numEmptyIndexSlotsAllocated];
  328. ibSlot->m_size=size;
  329. ibSlot->m_start=pIB->m_startFreeIndex;
  330. ibSlot->m_IB=pIB;
  331. //Link to IB list of slots
  332. ibSlot->m_nextSameIB=pIB->m_usedSlots;
  333. ibSlot->m_prevSameIB=NULL; //this will be the new head
  334. if (pIB->m_usedSlots)
  335. pIB->m_usedSlots->m_prevSameIB=ibSlot;
  336. ibSlot->m_prevSameSize=ibSlot->m_nextSameSize=NULL;
  337. pIB->m_usedSlots=ibSlot;
  338. pIB->m_startFreeIndex += size;
  339. m_numEmptyIndexSlotsAllocated++;
  340. return ibSlot;
  341. }
  342. }
  343. pIB = pIB->m_nextIB;
  344. }
  345. pIB=m_W3DIndexBuffers; //save old list head
  346. //Didn't find any index buffers with room, create a new one
  347. DEBUG_ASSERTCRASH(m_numEmptyIndexBuffersAllocated < MAX_INDEX_BUFFERS_CREATED, ("Reached Max Static IB Shadow Geometry"));
  348. if (m_numEmptyIndexBuffersAllocated < MAX_INDEX_BUFFERS_CREATED)
  349. {
  350. m_W3DIndexBuffers = &m_W3DEmptyIndexBuffers[m_numEmptyIndexBuffersAllocated];
  351. m_W3DIndexBuffers->m_nextIB=pIB; //link to list
  352. m_numEmptyIndexBuffersAllocated++;
  353. pIB=m_W3DIndexBuffers; //get new list head
  354. Int ibSize=__max(DEFAULT_INDEX_BUFFER_SIZE,size);
  355. pIB->m_DX8IndexBuffer=NEW_REF(DX8IndexBufferClass,(ibSize,DX8IndexBufferClass::USAGE_DEFAULT));
  356. pIB->m_startFreeIndex=size;
  357. pIB->m_size=ibSize;
  358. ibSlot=&m_W3DIndexBufferEmptySlots[m_numEmptyIndexSlotsAllocated];
  359. m_numEmptyIndexSlotsAllocated++;
  360. pIB->m_usedSlots=ibSlot;
  361. ibSlot->m_size=size;
  362. ibSlot->m_start=0;
  363. ibSlot->m_IB=pIB;
  364. ibSlot->m_prevSameIB=ibSlot->m_nextSameIB=NULL;
  365. ibSlot->m_prevSameSize=ibSlot->m_nextSameSize=NULL;
  366. return ibSlot;
  367. }
  368. return NULL;
  369. }