vegetablevb_allocator.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "std3d.h"
00025 
00026 
00027 #include "nel/3d/vegetablevb_allocator.h"
00028 #include "nel/3d/vegetable_def.h"
00029 
00030 
00031 using namespace std;
00032 using namespace NLMISC;
00033 
00034 namespace NL3D
00035 {
00036 
00037 
00038 /*
00039     Once a reallocation of a VB occurs, how many vertices we add to the re-allocation, to avoid
00040     as possible reallocations.
00041 */
00042 #define NL3D_VEGETABLE_VERTEX_ALLOCATE_SECURITY     1024
00043 /*
00044     The start size of the array.
00045 */
00046 #define NL3D_VEGETABLE_VERTEX_ALLOCATE_START        4048
00047 
00048 
00049 #define NL3D_VEGETABLE_VERTEX_FREE_MEMORY_RESERVE   1024
00050 
00051 
00052 // ***************************************************************************
00053 CVegetableVBAllocator::CVegetableVBAllocator()
00054 {
00055     _Type= VBTypeUnlit;
00056     _MaxVertexInBufferHard= 0;
00057 
00058     // Init free list
00059     _VertexFreeMemory.reserve(NL3D_VEGETABLE_VERTEX_FREE_MEMORY_RESERVE);
00060     _NumVerticesAllocated= 0;
00061 
00062     // Init vbhard
00063     _VBHardOk= false;
00064     _AGPBufferPtr= NULL;
00065     _RAMBufferPtr= NULL;
00066 }
00067 
00068 
00069 // ***************************************************************************
00070 void            CVegetableVBAllocator::init(TVBType type, uint maxVertexInBufferHard)
00071 {
00072     _Type= type;
00073     _MaxVertexInBufferHard= maxVertexInBufferHard;
00074 
00075     // According to _Type, build VB format, and create VertexProgram
00076     setupVBFormat();
00077 }
00078 
00079 
00080 // ***************************************************************************
00081 CVegetableVBAllocator::~CVegetableVBAllocator()
00082 {
00083     clear();
00084 }
00085 
00086 // ***************************************************************************
00087 void            CVegetableVBAllocator::updateDriver(IDriver *driver)
00088 {
00089     // test change of driver.
00090     nlassert(driver && !_VBHard.isLocked());
00091     // If change of driver
00092     if( _Driver==NULL || driver!=_Driver || (!_VBHard.isResident() && (_VBHard.capacity()!=0)))
00093     {
00094         // delete old VBHard.
00095         deleteVertexBufferHard();
00096         _Driver= driver;
00097         _VBHardOk= (_MaxVertexInBufferHard>0) && (_Driver->supportVertexBufferHard());
00098         /* Because so much lock/unlock are performed during a frame (refine/clip etc...).
00099             we must disable VBHard for ATI Gl extension.
00100             NB: CLandscape don't do this and fast copy the entire VB each frame.
00101             This is not possible for vegetables because the VB describe all Vegetable around the camera, not only
00102             what is in frustrum. Hence a fast copy each frame would copy far too much unseen vertices (4x).
00103         */
00104         if(_Driver->slowUnlockVertexBufferHard())
00105             _VBHardOk= false;
00106 
00107         // Driver must support VP.
00108         nlassert(_Driver->isVertexProgramSupported());
00109 
00110         // must reallocate the VertexBuffer.
00111         if( _NumVerticesAllocated>0 )
00112             allocateVertexBufferAndFillVBHard(_NumVerticesAllocated);
00113     }
00114     else
00115     {
00116         // if VBHard possible, and if vbHardDeleted but space needed, reallocate.
00117         if( _VBHardOk && _VBHard.getNumVertices()==0 && _NumVerticesAllocated>0 )
00118             allocateVertexBufferAndFillVBHard(_NumVerticesAllocated);
00119     }
00120 
00121 }
00122 
00123 // ***************************************************************************
00124 void            CVegetableVBAllocator::clear()
00125 {
00126     // clear list.
00127     _VertexFreeMemory.clear();
00128     _NumVerticesAllocated= 0;
00129 
00130     // must unlock for vbhard and vbsoft
00131     unlockBuffer();
00132 
00133     // delete the VB.
00134     deleteVertexBufferHard();
00135     // really delete the VB soft too
00136     _VBSoft.deleteAllVertices();
00137 
00138     // clear other states.
00139     _Driver= NULL;
00140     _VBHardOk= false;
00141 }
00142 
00143 
00144 // ***************************************************************************
00145 void            CVegetableVBAllocator::lockBuffer()
00146 {
00147     // force unlock
00148     unlockBuffer();
00149 
00150     // need to lock only if the VBHard is created
00151     if(_VBHardOk)
00152     {
00153         // lock the VBHard for writing
00154         _VBHard.lock(_VBAHard);
00155         _AGPBufferPtr=(uint8*)_VBAHard.getVertexCoordPointer();
00156 
00157         // lock the Input VertexBuffer for reading
00158         _VBSoft.lock(_VBASoft);
00159         _RAMBufferPtr=(const uint8*)_VBASoft.getVertexCoordPointer();
00160     }
00161 }
00162 
00163 // ***************************************************************************
00164 void            CVegetableVBAllocator::unlockBuffer()
00165 {
00166     // unlock the VBHard
00167     _VBAHard.unlock();
00168     _AGPBufferPtr= NULL;
00169 
00170     // unlock the VBSoft
00171     _VBASoft.unlock();
00172     _RAMBufferPtr= NULL;
00173 }
00174 
00175 
00176 // ***************************************************************************
00177 uint            CVegetableVBAllocator::getNumUserVerticesAllocated() const
00178 {
00179     // get the number of vertices which are allocated by allocateVertex().
00180     return _NumVerticesAllocated - _VertexFreeMemory.size();
00181 }
00182 
00183 // ***************************************************************************
00184 bool            CVegetableVBAllocator::exceedMaxVertexInBufferHard(uint numAddVerts) const
00185 {
00186     return (getNumUserVerticesAllocated() + numAddVerts) > _MaxVertexInBufferHard;
00187 }
00188 
00189 
00190 // ***************************************************************************
00191 uint            CVegetableVBAllocator::allocateVertex()
00192 {
00193     // if no more free, allocate.
00194     if( _VertexFreeMemory.size()==0 )
00195     {
00196         // enlarge capacity.
00197         uint    newResize;
00198         if(_NumVerticesAllocated==0)
00199             newResize= NL3D_VEGETABLE_VERTEX_ALLOCATE_START;
00200         else
00201             newResize= NL3D_VEGETABLE_VERTEX_ALLOCATE_SECURITY;
00202         // try to not overlap _MaxVertexInBufferHard limit, to avoid VBufferHard to be disabled.
00203         if(_NumVerticesAllocated<_MaxVertexInBufferHard && _NumVerticesAllocated+newResize > _MaxVertexInBufferHard)
00204         {
00205             newResize= _MaxVertexInBufferHard - _NumVerticesAllocated;
00206         }
00207         _NumVerticesAllocated+= newResize;
00208         // re-allocate VB.
00209         allocateVertexBufferAndFillVBHard(_NumVerticesAllocated);
00210         // resize infos on vertices.
00211         _VertexInfos.resize(_NumVerticesAllocated);
00212 
00213         // Fill list of free elements.
00214         for(uint i=0;i<newResize;i++)
00215         {
00216             // create a new entry which points to this vertex.
00217             // the list is made so allocation is in growing order.
00218             _VertexFreeMemory.push_back( _NumVerticesAllocated - (i+1) );
00219 
00220             // Mark as free the new vertices. (Debug).
00221             _VertexInfos[_NumVerticesAllocated - (i+1)].Free= true;
00222         }
00223     }
00224 
00225     // get a vertex (pop_back).
00226     uint    id= _VertexFreeMemory.back();
00227     // delete this vertex free entry.
00228     _VertexFreeMemory.pop_back();
00229 
00230     // check and Mark as not free the vertex. (Debug).
00231     nlassert(id<_NumVerticesAllocated);
00232     nlassert(_VertexInfos[id].Free);
00233     _VertexInfos[id].Free= false;
00234 
00235 
00236     return id;
00237 }
00238 
00239 // ***************************************************************************
00240 void            CVegetableVBAllocator::deleteVertex(uint vid)
00241 {
00242     // check and Mark as free the vertex. (Debug).
00243     nlassert(vid<_NumVerticesAllocated);
00244     nlassert(!_VertexInfos[vid].Free);
00245     _VertexInfos[vid].Free= true;
00246 
00247     // Add this vertex to the free list.
00248     // create a new entry which points to this vertex.
00249     _VertexFreeMemory.push_back( vid );
00250 }
00251 
00252 // ***************************************************************************
00253 void            CVegetableVBAllocator::flushVertex(uint i)
00254 {
00255     if(_VBHardOk)
00256     {
00257         nlassert(_VBHard.getNumVertices() && _VBHard.isLocked() && _VBSoft.isLocked());
00258 
00259         // copy the VB soft to the VBHard.
00260         uint    size= _VBSoft.getVertexSize();
00261         const void  *src= _RAMBufferPtr + i*size;
00262         void        *dst= _AGPBufferPtr + i*size;
00263         CHECK_VBA_RANGE(_VBAHard, (uint8 *) dst, size);
00264         CHECK_VBA_RANGE(_VBASoft, (uint8 *) src, size);
00265         memcpy(dst, src, size);
00266     }
00267 }
00268 
00269 // ***************************************************************************
00270 void            CVegetableVBAllocator::activate()
00271 {
00272     nlassert(_Driver);
00273     nlassert(!_VBHard.isLocked());
00274     nlassert(!_VBSoft.isLocked());
00275 
00276     // Activate VB.
00277     if(_VBHard.getNumVertices())
00278         _Driver->activeVertexBuffer(_VBHard);
00279     else
00280         _Driver->activeVertexBuffer(_VBSoft);
00281 }
00282 
00283 
00284 // ***************************************************************************
00285 // ***************************************************************************
00286 // Vertex Buffer hard.
00287 // ***************************************************************************
00288 // ***************************************************************************
00289 
00290 
00291 // ***************************************************************************
00292 void                CVegetableVBAllocator::deleteVertexBufferHard()
00293 {
00294     // must unlock VBhard before.
00295     unlockBuffer();
00296 
00297     // test (refptr) if the object still exist in memory.
00298     if(_VBHard.getNumVertices()!=0)
00299     {
00300         // A vbufferhard should still exist only if driver still exist.
00301         nlassert(_Driver!=NULL);
00302 
00303         // delete it from driver.
00304         _VBHard.deleteAllVertices ();
00305     }
00306 
00307 }
00308 
00309 // ***************************************************************************
00310 void                CVegetableVBAllocator::allocateVertexBufferAndFillVBHard(uint32 numVertices)
00311 {
00312     // no allocation must be done if the Driver is not setuped, or if the driver has been deleted by refPtr.
00313     nlassert(_Driver);
00314 
00315     // must unlock VBhard and VBSoft before.
00316     bool    wasLocked= bufferLocked();
00317     unlockBuffer();
00318 
00319     // resize the Soft VB.
00320     _VBSoft.setNumVertices(numVertices);
00321 
00322     // try to allocate a vbufferhard if possible.
00323     if( _VBHardOk )
00324     {
00325         /* Prefer allocate the VBHard with the Max Vertex count only ONCE,
00326             to avoid problems with AGP allocation
00327             The problem is with 50000 AGP vertices, it costs 3 Mo. If we do iterative allocation
00328             (500 Ko, 600 Ko, 700 Ko,.....)
00329             we may have problem with free holes (Vegetable could no more enter in the 16 or 8 Mo AGP limit!)
00330         */
00331         if(_VBHard.getNumVertices() != _MaxVertexInBufferHard)
00332         {
00333             // delete possible old _VBHard.
00334             if(_VBHard.getNumVertices()!=0)
00335             {
00336                 // VertexBufferHard lifetime < Driver lifetime.
00337                 nlassert(_Driver!=NULL);
00338                 _VBHard.deleteAllVertices();
00339             }
00340 
00341             // try to create new one, in AGP Ram
00342             // If too many vertices wanted, abort VBHard.
00343             if(numVertices <= _MaxVertexInBufferHard)
00344             {
00345                 _VBHard = _VBSoft;
00346                 _VBHard.setPreferredMemory(CVertexBuffer::AGPPreferred, false);
00347                 _VBHard.setNumVertices (_MaxVertexInBufferHard);
00348 
00349                 // Force this VB to be hard
00350                 nlverify (_Driver->activeVertexBuffer (_VBHard));
00351                 nlassert (_VBHard.isResident());
00352 
00353                 // if fails, abort VBHard.
00354                 if (_VBHard.getLocation() == CVertexBuffer::RAMResident)
00355                     _VBHard.deleteAllVertices();
00356 
00357                 // Set Name For lock Profiling.
00358                 if(_VBHard.getNumVertices()!=0)
00359                     _VBHard.setName("VegetableVB");
00360             }
00361             else
00362                 _VBHard.deleteAllVertices();
00363 
00364             // If KO, never try again.
00365             if(_VBHard.getNumVertices()==0)
00366                 _VBHardOk= false;
00367         }
00368     }
00369 
00370     // if still OK, must refill the VBHard. Slow, but rare
00371     if(_VBHardOk)
00372     {
00373         // else, fill this AGP VBuffer Hard.
00374         // lock before the AGP buffer
00375         lockBuffer();
00376 
00377         // copy all the vertices to AGP.
00378         memcpy(_AGPBufferPtr, _RAMBufferPtr, _VBSoft.getVertexSize() * numVertices);
00379 
00380         // If was not locked before, unlock this VB
00381         if(!wasLocked)
00382             unlockBuffer();
00383     }
00384 
00385     //nlinfo("VEGET: Alloc %d verts. %s", numVertices, _VBHardOk?"VBHard":"VBSoft");
00386 }
00387 
00388 
00389 // ***************************************************************************
00390 void                CVegetableVBAllocator::setupVBFormat()
00391 {
00392     // Build the Vertex Format.
00393     _VBSoft.clearValueEx();
00394 
00395     // if lighted, need world space normal and AmbientColor for each vertex.
00396     if( _Type == VBTypeLighted )
00397     {
00398         _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_POS,    CVertexBuffer::Float3);     // v[0]
00399         _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_NORMAL, CVertexBuffer::Float3);     // v[2]
00400         _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_BENDINFO,   CVertexBuffer::Float3);     // v[9]
00401     }
00402     // If unlit
00403     else
00404     {
00405         // slightly different VertexProgram, v[0].w== BendWeight, and v[9].x== v[0].norm()
00406         _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_POS,        CVertexBuffer::Float4);     // v[0]
00407         // Unlit VP has BlendDistance in v[9].w
00408         _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_BENDINFO,   CVertexBuffer::Float4);     // v[9]
00409     }
00410     _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_COLOR0,     CVertexBuffer::UChar4);     // v[3]
00411     _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_COLOR1,     CVertexBuffer::UChar4);     // v[4]
00412     _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_TEX0,       CVertexBuffer::Float2);     // v[8]
00413     _VBSoft.addValueEx(NL3D_VEGETABLE_VPPOS_CENTER,     CVertexBuffer::Float3);     // v[10]
00414     _VBSoft.initEx();
00415 
00416 }
00417 
00418 
00419 
00420 } // NL3D

Generated on Thu Jan 7 08:26:31 2010 for NeL by  doxygen 1.6.1