| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- #include "Common/Debug.h"
- #include "W3DDevice/GameClient/W3DBufferManager.h"
- W3DBufferManager *TheW3DBufferManager=NULL; //singleton
- static int FVFTypeIndexList[W3DBufferManager::MAX_FVF]=
- {
- D3DFVF_XYZ,
- D3DFVF_XYZ|D3DFVF_DIFFUSE,
- D3DFVF_XYZ|D3DFVF_TEX1,
- D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1,
- D3DFVF_XYZ|D3DFVF_TEX2,
- D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX2,
- D3DFVF_XYZ|D3DFVF_NORMAL,
- D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE,
- D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
- D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1,
- D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2,
- D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX2,
- D3DFVF_XYZRHW,
- D3DFVF_XYZRHW|D3DFVF_DIFFUSE,
- D3DFVF_XYZRHW|D3DFVF_TEX1,
- D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1,
- D3DFVF_XYZRHW|D3DFVF_TEX2,
- D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX2
- };
- Int W3DBufferManager::getDX8Format(VBM_FVF_TYPES format)
- {
- return FVFTypeIndexList[format];
- }
- W3DBufferManager::W3DBufferManager(void)
- {
- m_numEmptySlotsAllocated=0;
- m_numEmptyVertexBuffersAllocated=0;
- m_numEmptyIndexSlotsAllocated=0;
- m_numEmptyIndexBuffersAllocated=0;
- for (Int i=0; i<MAX_FVF; i++)
- m_W3DVertexBuffers[i]=NULL;
- for (i=0; i<MAX_FVF; i++)
- for (Int j=0; j<MAX_VB_SIZES; j++)
- m_W3DVertexBufferSlots[i][j]=NULL;
- m_W3DIndexBuffers=NULL;
- for (Int j=0; j<MAX_IB_SIZES; j++)
- m_W3DIndexBufferSlots[j]=NULL;
- }
- W3DBufferManager::~W3DBufferManager(void)
- {
- freeAllSlots();
- freeAllBuffers();
- }
- void W3DBufferManager::freeAllSlots(void)
- {
- Int i,j;
- for (i=0; i<MAX_FVF; i++)
- {
- for (j=0; j<MAX_VB_SIZES; j++)
- {
- //Release all slots allocated for each size
- W3DVertexBufferSlot *vbSlot = m_W3DVertexBufferSlots[i][j];
- while (vbSlot)
- {
- if (vbSlot->m_prevSameVB)
- vbSlot->m_prevSameVB->m_nextSameVB=vbSlot->m_nextSameVB;
- else
- vbSlot->m_VB->m_usedSlots=NULL;
- if (vbSlot->m_nextSameVB)
- vbSlot->m_nextSameVB->m_prevSameVB=vbSlot->m_prevSameVB;
- vbSlot=vbSlot->m_nextSameSize;
- m_numEmptySlotsAllocated--;
- }
- m_W3DVertexBufferSlots[i][j]=NULL;
- }
- }
- for (j=0; j<MAX_IB_SIZES; j++)
- {
- //Release all slots allocated for each size
- W3DIndexBufferSlot *ibSlot = m_W3DIndexBufferSlots[j];
- while (ibSlot)
- {
- if (ibSlot->m_prevSameIB)
- ibSlot->m_prevSameIB->m_nextSameIB=ibSlot->m_nextSameIB;
- else
- ibSlot->m_IB->m_usedSlots=NULL;
- if (ibSlot->m_nextSameIB)
- ibSlot->m_nextSameIB->m_prevSameIB=ibSlot->m_prevSameIB;
- ibSlot=ibSlot->m_nextSameSize;
- m_numEmptyIndexSlotsAllocated--;
- }
- m_W3DIndexBufferSlots[j]=NULL;
- }
- DEBUG_ASSERTCRASH(m_numEmptySlotsAllocated==0, ("Failed to free all empty vertex buffer slots"));
- DEBUG_ASSERTCRASH(m_numEmptyIndexSlotsAllocated==0, ("Failed to free all empty index buffer slots"));
- }
- void W3DBufferManager::freeAllBuffers(void)
- {
- Int i;
- //Make sure all slots are free
- freeAllSlots(); ///<release all slots to pool.
- for (i=0; i<MAX_FVF; i++)
- {
- W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
- while (vb)
- { DEBUG_ASSERTCRASH(vb->m_usedSlots == NULL, ("Freeing Non-Empty Vertex Buffer"));
- REF_PTR_RELEASE(vb->m_DX8VertexBuffer);
- m_numEmptyVertexBuffersAllocated--;
- vb=vb->m_nextVB; //get next vertex buffer of this type
- }
- m_W3DVertexBuffers[i]=NULL;
- }
- W3DIndexBuffer *ib = m_W3DIndexBuffers;
- while (ib)
- { DEBUG_ASSERTCRASH(ib->m_usedSlots == NULL, ("Freeing Non-Empty Index Buffer"));
- REF_PTR_RELEASE(ib->m_DX8IndexBuffer);
- m_numEmptyIndexBuffersAllocated--;
- ib=ib->m_nextIB; //get next vertex buffer of this type
- }
- m_W3DIndexBuffers=NULL;
- DEBUG_ASSERTCRASH(m_numEmptyVertexBuffersAllocated==0, ("Failed to free all empty vertex buffers"));
- DEBUG_ASSERTCRASH(m_numEmptyIndexBuffersAllocated==0, ("Failed to free all empty index buffers"));
- }
- void W3DBufferManager::ReleaseResources(void)
- {
- for (Int i=0; i<MAX_FVF; i++)
- {
- W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
- while (vb)
- {
- REF_PTR_RELEASE(vb->m_DX8VertexBuffer);
- vb=vb->m_nextVB; //get next vertex buffer of this type
- }
- }
- W3DIndexBuffer *ib = m_W3DIndexBuffers;
- while (ib)
- {
- REF_PTR_RELEASE(ib->m_DX8IndexBuffer);
- ib=ib->m_nextIB; //get next vertex buffer of this type
- }
- }
- Bool W3DBufferManager::ReAcquireResources(void)
- {
- for (Int i=0; i<MAX_FVF; i++)
- {
- W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
- while (vb)
- { DEBUG_ASSERTCRASH( vb->m_DX8VertexBuffer == NULL, ("ReAcquire of existing vertex buffer"));
- vb->m_DX8VertexBuffer=NEW_REF(DX8VertexBufferClass,(FVFTypeIndexList[vb->m_format],vb->m_size,DX8VertexBufferClass::USAGE_DEFAULT));
- DEBUG_ASSERTCRASH( vb->m_DX8VertexBuffer, ("Failed ReAcquire of vertex buffer"));
- if (!vb->m_DX8VertexBuffer)
- return FALSE;
- vb=vb->m_nextVB; //get next vertex buffer of this type
- }
- }
- W3DIndexBuffer *ib = m_W3DIndexBuffers;
- while (ib)
- { DEBUG_ASSERTCRASH( ib->m_DX8IndexBuffer == NULL, ("ReAcquire of existing index buffer"));
- ib->m_DX8IndexBuffer=NEW_REF(DX8IndexBufferClass,(ib->m_size,DX8IndexBufferClass::USAGE_DEFAULT));
- DEBUG_ASSERTCRASH( ib->m_DX8IndexBuffer, ("Failed ReAcquire of index buffer"));
- if (!ib->m_DX8IndexBuffer)
- return FALSE;
- ib=ib->m_nextIB; //get next vertex buffer of this type
- }
- return TRUE;
- }
- /**Searches through previously allocated vertex buffer slots and returns a matching type. If none found,
- creates a new slot and adds it to the pool. Returns an integer slotId used to reference the VB.
- Returns -1 in case of failure.
- */
- W3DBufferManager::W3DVertexBufferSlot *W3DBufferManager::getSlot(VBM_FVF_TYPES fvfType, Int size)
- {
- W3DVertexBufferSlot *vbSlot=NULL;
- //round size to next multiple of minimum slot size.
- //should help avoid fragmentation.
- size = (size + (MIN_SLOT_SIZE-1)) & (~(MIN_SLOT_SIZE-1));
- Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
- DEBUG_ASSERTCRASH(sizeIndex < MAX_VB_SIZES && size, ("Allocating too large vertex buffer slot"));
- if ((vbSlot=m_W3DVertexBufferSlots[fvfType][sizeIndex]) != 0)
- { //found a previously allocated slot matching required size
- m_W3DVertexBufferSlots[fvfType][sizeIndex]=vbSlot->m_nextSameSize;
- if (vbSlot->m_nextSameSize)
- vbSlot->m_nextSameSize->m_prevSameSize=NULL;
- return vbSlot;
- }
- else
- { //need to allocate a new slot
- return allocateSlotStorage(fvfType, size);
- }
- return NULL;
- }
- /**Returns vertex buffer space back to pool so it can be reused later*/
- void W3DBufferManager::releaseSlot(W3DVertexBufferSlot *vbSlot)
- {
- Int sizeIndex = (vbSlot->m_size >> MIN_SLOT_SIZE_SHIFT)-1;
- vbSlot->m_nextSameSize=m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex];
- if (m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex])
- m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex]->m_prevSameSize=vbSlot;
- m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex]=vbSlot;
- }
- /**Reserves space inside existing vertex buffer or allocates a new one to fit the required size.
- */
- W3DBufferManager::W3DVertexBufferSlot * W3DBufferManager::allocateSlotStorage(VBM_FVF_TYPES fvfType, Int size)
- {
- W3DVertexBuffer *pVB;
- W3DVertexBufferSlot *vbSlot;
- // Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
- DEBUG_ASSERTCRASH(m_numEmptySlotsAllocated < MAX_NUMBER_SLOTS, ("Nore more VB Slots"));
- pVB=m_W3DVertexBuffers[fvfType];
- while (pVB)
- {
- if ((pVB->m_size - pVB->m_startFreeIndex) >= size)
- { //found enough free space in this vertex buffer
- if (m_numEmptySlotsAllocated < MAX_NUMBER_SLOTS)
- { //we're allowing more slots to be allocated.
- vbSlot=&m_W3DVertexBufferEmptySlots[m_numEmptySlotsAllocated];
- vbSlot->m_size=size;
- vbSlot->m_start=pVB->m_startFreeIndex;
- vbSlot->m_VB=pVB;
- //Link to VB list of slots
- vbSlot->m_nextSameVB=pVB->m_usedSlots;
- vbSlot->m_prevSameVB=NULL; //this will be the new head
- if (pVB->m_usedSlots)
- pVB->m_usedSlots->m_prevSameVB=vbSlot;
- vbSlot->m_prevSameSize=vbSlot->m_nextSameSize=NULL;
- pVB->m_usedSlots=vbSlot;
- pVB->m_startFreeIndex += size;
- m_numEmptySlotsAllocated++;
- return vbSlot;
- }
- }
- pVB = pVB->m_nextVB;
- }
- pVB=m_W3DVertexBuffers[fvfType]; //save old list head
- //Didn't find any vertex buffers with room, create a new one
- DEBUG_ASSERTCRASH(m_numEmptyVertexBuffersAllocated < MAX_VERTEX_BUFFERS_CREATED, ("Reached Max Static VB Shadow Geometry"));
- if (m_numEmptyVertexBuffersAllocated < MAX_VERTEX_BUFFERS_CREATED)
- {
- m_W3DVertexBuffers[fvfType] = &m_W3DEmptyVertexBuffers[m_numEmptyVertexBuffersAllocated];
- m_W3DVertexBuffers[fvfType]->m_nextVB=pVB; //link to list
- m_numEmptyVertexBuffersAllocated++;
-
- pVB=m_W3DVertexBuffers[fvfType]; //get new list head
- Int vbSize=__max(DEFAULT_VERTEX_BUFFER_SIZE,size);
- pVB->m_DX8VertexBuffer=NEW_REF(DX8VertexBufferClass,(FVFTypeIndexList[fvfType],vbSize,DX8VertexBufferClass::USAGE_DEFAULT));
- pVB->m_format=fvfType;
- pVB->m_startFreeIndex=size;
- pVB->m_size=vbSize;
- vbSlot=&m_W3DVertexBufferEmptySlots[m_numEmptySlotsAllocated];
- m_numEmptySlotsAllocated++;
- pVB->m_usedSlots=vbSlot;
- vbSlot->m_size=size;
- vbSlot->m_start=0;
- vbSlot->m_VB=pVB;
- vbSlot->m_prevSameVB=vbSlot->m_nextSameVB=NULL;
- vbSlot->m_prevSameSize=vbSlot->m_nextSameSize=NULL;
- return vbSlot;
- }
- return NULL;
- }
- //******************************** Index Buffer code ******************************************************
- /**Searches through previously allocated index buffer slots and returns a matching type. If none found,
- creates a new slot and adds it to the pool. Returns an integer slotId used to reference the VB.
- Returns -1 in case of failure.
- */
- W3DBufferManager::W3DIndexBufferSlot *W3DBufferManager::getSlot(Int size)
- {
- W3DIndexBufferSlot *ibSlot=NULL;
- //round size to next multiple of minimum slot size.
- //should help avoid fragmentation.
- size = (size + (MIN_SLOT_SIZE-1)) & (~(MIN_SLOT_SIZE-1));
- Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
- DEBUG_ASSERTCRASH(sizeIndex < MAX_IB_SIZES && size, ("Allocating too large index buffer slot"));
- if ((ibSlot=m_W3DIndexBufferSlots[sizeIndex]) != 0)
- { //found a previously allocated slot matching required size
- m_W3DIndexBufferSlots[sizeIndex]=ibSlot->m_nextSameSize;
- if (ibSlot->m_nextSameSize)
- ibSlot->m_nextSameSize->m_prevSameSize=NULL;
- return ibSlot;
- }
- else
- { //need to allocate a new slot
- return allocateSlotStorage(size);
- }
- return NULL;
- }
- /**Returns index buffer space back to pool so it can be reused later*/
- void W3DBufferManager::releaseSlot(W3DIndexBufferSlot *ibSlot)
- {
- Int sizeIndex = (ibSlot->m_size >> MIN_SLOT_SIZE_SHIFT)-1;
- ibSlot->m_nextSameSize=m_W3DIndexBufferSlots[sizeIndex];
- if (m_W3DIndexBufferSlots[sizeIndex])
- m_W3DIndexBufferSlots[sizeIndex]->m_prevSameSize=ibSlot;
- m_W3DIndexBufferSlots[sizeIndex]=ibSlot;
- }
- /**Reserves space inside existing index buffer or allocates a new one to fit the required size.
- */
- W3DBufferManager::W3DIndexBufferSlot * W3DBufferManager::allocateSlotStorage(Int size)
- {
- W3DIndexBuffer *pIB;
- W3DIndexBufferSlot *ibSlot;
- // Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
- DEBUG_ASSERTCRASH(m_numEmptyIndexSlotsAllocated < MAX_NUMBER_SLOTS, ("Nore more IB Slots"));
- pIB=m_W3DIndexBuffers;
- while (pIB)
- {
- if ((pIB->m_size - pIB->m_startFreeIndex) >= size)
- { //found enough free space in this index buffer
- if (m_numEmptyIndexSlotsAllocated < MAX_NUMBER_SLOTS)
- { //we're allowing more slots to be allocated.
- ibSlot=&m_W3DIndexBufferEmptySlots[m_numEmptyIndexSlotsAllocated];
- ibSlot->m_size=size;
- ibSlot->m_start=pIB->m_startFreeIndex;
- ibSlot->m_IB=pIB;
- //Link to IB list of slots
- ibSlot->m_nextSameIB=pIB->m_usedSlots;
- ibSlot->m_prevSameIB=NULL; //this will be the new head
- if (pIB->m_usedSlots)
- pIB->m_usedSlots->m_prevSameIB=ibSlot;
- ibSlot->m_prevSameSize=ibSlot->m_nextSameSize=NULL;
- pIB->m_usedSlots=ibSlot;
- pIB->m_startFreeIndex += size;
- m_numEmptyIndexSlotsAllocated++;
- return ibSlot;
- }
- }
- pIB = pIB->m_nextIB;
- }
- pIB=m_W3DIndexBuffers; //save old list head
- //Didn't find any index buffers with room, create a new one
- DEBUG_ASSERTCRASH(m_numEmptyIndexBuffersAllocated < MAX_INDEX_BUFFERS_CREATED, ("Reached Max Static IB Shadow Geometry"));
- if (m_numEmptyIndexBuffersAllocated < MAX_INDEX_BUFFERS_CREATED)
- {
- m_W3DIndexBuffers = &m_W3DEmptyIndexBuffers[m_numEmptyIndexBuffersAllocated];
- m_W3DIndexBuffers->m_nextIB=pIB; //link to list
- m_numEmptyIndexBuffersAllocated++;
-
- pIB=m_W3DIndexBuffers; //get new list head
- Int ibSize=__max(DEFAULT_INDEX_BUFFER_SIZE,size);
- pIB->m_DX8IndexBuffer=NEW_REF(DX8IndexBufferClass,(ibSize,DX8IndexBufferClass::USAGE_DEFAULT));
- pIB->m_startFreeIndex=size;
- pIB->m_size=ibSize;
- ibSlot=&m_W3DIndexBufferEmptySlots[m_numEmptyIndexSlotsAllocated];
- m_numEmptyIndexSlotsAllocated++;
- pIB->m_usedSlots=ibSlot;
- ibSlot->m_size=size;
- ibSlot->m_start=0;
- ibSlot->m_IB=pIB;
- ibSlot->m_prevSameIB=ibSlot->m_nextSameIB=NULL;
- ibSlot->m_prevSameSize=ibSlot->m_nextSameSize=NULL;
- return ibSlot;
- }
- return NULL;
- }
|