# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

driver_opengl_vertex_buffer_hard.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000-2002 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "stdopengl.h"
00027 
00028 #include "driver_opengl_vertex_buffer_hard.h"
00029 
00030 
00031 using   namespace std;
00032 using   namespace NLMISC;
00033 
00034 namespace NL3D 
00035 {
00036 
00037 
00038 
00039 // ***************************************************************************
00040 // ***************************************************************************
00041 // ***************************************************************************
00042 //
00043 // VBHard interface for both NVidia / ATI extension.
00044 //
00045 // ***************************************************************************
00046 // ***************************************************************************
00047 // ***************************************************************************
00048 
00049 
00050 
00051 // ***************************************************************************
00052 IVertexArrayRange::IVertexArrayRange(CDriverGL *drv)
00053 {
00054         _Driver= drv;
00055 }
00056 // ***************************************************************************
00057 IVertexArrayRange::~IVertexArrayRange()
00058 {
00059 }
00060 
00061 // ***************************************************************************
00062 IVertexBufferHardGL::IVertexBufferHardGL(CDriverGL *drv)
00063 {
00064         _Driver= drv;
00065         NVidiaVertexBufferHard= false;
00066         ATIVertexBufferHard= false;
00067         GPURenderingAfterFence= false;
00068 }
00069 // ***************************************************************************
00070 IVertexBufferHardGL::~IVertexBufferHardGL()
00071 {
00072 }
00073 
00074 
00075 
00076 // ***************************************************************************
00077 // ***************************************************************************
00078 // ***************************************************************************
00079 //
00080 // NVidia implementation
00081 //
00082 // ***************************************************************************
00083 // ***************************************************************************
00084 // ***************************************************************************
00085 
00086 
00087 
00088 // ***************************************************************************
00089 // CVertexArrayRangeNVidia
00090 // ***************************************************************************
00091 
00092 
00093 // ***************************************************************************
00094 CVertexArrayRangeNVidia::CVertexArrayRangeNVidia(CDriverGL *drv) : IVertexArrayRange(drv)
00095 {
00096         _VertexArrayPtr= NULL;
00097         _VertexArraySize= 0;
00098 }
00099 
00100 
00101 // ***************************************************************************
00102 bool                    CVertexArrayRangeNVidia::allocate(uint32 size, IDriver::TVBHardType vbType)
00103 {
00104         nlassert(_VertexArrayPtr==NULL);
00105 
00106 #ifdef  NL_OS_WINDOWS
00107         // try to allocate AGP or VRAM data.
00108         switch(vbType)
00109         {
00110         case IDriver::VBHardAGP: 
00111                 _VertexArrayPtr= wglAllocateMemoryNV(size, 0, 0, 0.5f);
00112                 break;
00113         case IDriver::VBHardVRAM:
00114                 _VertexArrayPtr= wglAllocateMemoryNV(size, 0, 0, 1.0f);
00115                 break;
00116         };
00117 #endif  // NL_OS_WINDOWS
00118 
00119 
00120         // init the allocator.
00121         if(_VertexArrayPtr)
00122         {
00123                 /* Init with an alignment of 8. Not sure it is usefull, but GDC01_Performance.pdf papers talks about
00124                   "Data arrays must be 8-byte aligned". Don't know what "Data" is.
00125                 */
00126                 _HeapMemory.initHeap(_VertexArrayPtr, size, 8);
00127 
00128                 // set the size
00129                 _VertexArraySize= size;
00130         }
00131 
00132 
00133         return _VertexArrayPtr!=NULL;
00134 }
00135 
00136 
00137 // ***************************************************************************
00138 uint                    CVertexArrayRangeNVidia::sizeAllocated() const
00139 {
00140         return _VertexArraySize;
00141 }
00142 
00143 
00144 // ***************************************************************************
00145 void                    CVertexArrayRangeNVidia::free()
00146 {
00147         // release the ptr.
00148         if(_VertexArrayPtr)
00149         {
00150                 // reset the allocator.
00151                 _HeapMemory.reset();
00152 
00153 
00154                 // Free special memory.
00155 #ifdef  NL_OS_WINDOWS
00156                 wglFreeMemoryNV(_VertexArrayPtr);
00157 #endif  // NL_OS_WINDOWS
00158 
00159 
00160                 _VertexArrayPtr= NULL;
00161                 _VertexArraySize= 0;
00162         }
00163 }
00164 
00165 
00166 // ***************************************************************************
00167 void                    CVertexArrayRangeNVidia::enable()
00168 {
00169         // if not already enabled.
00170         if(_Driver->_CurrentVertexArrayRange!=this)
00171         {
00172                 // Setup the ptrs only if differnets from last time (may rarely happens)
00173                 if( _Driver->_NVCurrentVARSize != _VertexArraySize || _Driver->_NVCurrentVARPtr != _VertexArrayPtr)
00174                 {
00175                         // Yoyo: fucking NVidia Bug ?? must do this strange thing, this ensure that it is correclty setuped.
00176                         glFinish();
00177                         nglVertexArrayRangeNV(_VertexArraySize, _VertexArrayPtr);
00178                         glEnableClientState(GL_VERTEX_ARRAY_RANGE_NV);
00179                         glVertexPointer(3,GL_FLOAT, 0, _VertexArrayPtr);
00180                         // cache.
00181                         _Driver->_NVCurrentVARSize= _VertexArraySize;
00182                         _Driver->_NVCurrentVARPtr= _VertexArrayPtr;
00183                 }
00184                 // enable VAR. NB: flush is unesufull, so don't flush if extension is OK
00185                 glEnableClientState(_Driver->_Extensions.NVStateVARWithoutFlush);
00186                 _Driver->_CurrentVertexArrayRange= this;
00187         }
00188 }
00189 
00190 
00191 // ***************************************************************************
00192 void                    CVertexArrayRangeNVidia::disable()
00193 {
00194         // if not already disabled.
00195         if(_Driver->_CurrentVertexArrayRange!=NULL)
00196         {
00197                 // just disable the state, don't change VAR ptr setup.
00198                 // NB: flush is unesufull, so don't flush if extension is OK
00199                 glDisableClientState(_Driver->_Extensions.NVStateVARWithoutFlush);
00200                 _Driver->_CurrentVertexArrayRange= NULL;
00201         }
00202 }
00203 
00204 
00205 // ***************************************************************************
00206 void                    *CVertexArrayRangeNVidia::allocateVB(uint32 size)
00207 {
00208         return _HeapMemory.allocate(size);
00209 }
00210 
00211 
00212 // ***************************************************************************
00213 void                    CVertexArrayRangeNVidia::freeVB(void    *ptr)
00214 {
00215         _HeapMemory.free(ptr);
00216 }
00217 
00218 
00219 // ***************************************************************************
00220 IVertexBufferHardGL             *CVertexArrayRangeNVidia::createVBHardGL(uint16 vertexFormat, const uint8 *typeArray, uint32 numVertices)
00221 {
00222         // create a NVidia VBHard
00223         CVertexBufferHardGLNVidia       *newVbHard= new CVertexBufferHardGLNVidia(_Driver);
00224 
00225         // Init the format of the VB.
00226         newVbHard->initFormat(vertexFormat, typeArray, numVertices);
00227 
00228         // compute size to allocate.
00229         uint32  size= newVbHard->getVertexSize() * newVbHard->getNumVertices();
00230 
00231         // try to allocate
00232         void    *vertexPtr;
00233         if( allocated() )
00234         {
00235                  vertexPtr= allocateVB(size);
00236         }
00237 
00238         // If allocation fails.
00239         if( !vertexPtr )
00240         {
00241                 // just destroy this object (no free()).
00242                 delete newVbHard;
00243                 return NULL;
00244         }
00245         else
00246         {
00247                 // Ok, setup, and allocate the fence.
00248                 newVbHard->initGL(this, vertexPtr);
00249                 return newVbHard;
00250         }
00251 }
00252 
00253 
00254 // ***************************************************************************
00255 // CVertexBufferHardGLNVidia
00256 // ***************************************************************************
00257 
00258 
00259 // ***************************************************************************
00260 CVertexBufferHardGLNVidia::CVertexBufferHardGLNVidia(CDriverGL *drv) : IVertexBufferHardGL(drv)
00261 {
00262         _VertexArrayRange= NULL;
00263         _VertexPtr= NULL;
00264 
00265         GPURenderingAfterFence= false;
00266         _FenceSet= false;
00267 
00268         // Flag our type
00269         NVidiaVertexBufferHard= true;
00270 }
00271 
00272 
00273 // ***************************************************************************
00274 CVertexBufferHardGLNVidia::~CVertexBufferHardGLNVidia()
00275 {
00276         if(_VertexArrayRange)
00277         {
00278                 // Destroy Fence.
00279                 // First wait for completion.
00280                 finishFence();
00281                 // then delete.
00282                 nglDeleteFencesNV(1, &_Fence);
00283 
00284                 // Then free the VAR.
00285                 _VertexArrayRange->freeVB(_VertexPtr);
00286                 _VertexPtr= NULL;
00287                 _VertexArrayRange= NULL;
00288         }
00289 }
00290 
00291 
00292 // ***************************************************************************
00293 void            CVertexBufferHardGLNVidia::initGL(CVertexArrayRangeNVidia *var, void *vertexPtr)
00294 {
00295         _VertexArrayRange= var;
00296         _VertexPtr= vertexPtr;
00297         nglGenFencesNV(1, &_Fence);
00298 }
00299 
00300 
00301 // ***************************************************************************
00302 void            *CVertexBufferHardGLNVidia::lock()
00303 {
00304         // sync the 3d card with the system.
00305 
00306         // Ensure the GPU has finished with the current VBHard.
00307         finishFence();
00308         // If the user lock an activated VBHard, after rendering some primitives, we must stall the CPU
00309         if(GPURenderingAfterFence)
00310         {
00311                 // Set a fence at the current position in the command stream.
00312                 setFence();
00313                 // wait for him to finish.
00314                 finishFence();
00315                 // And so the GPU render all our primitives.
00316                 GPURenderingAfterFence= false;
00317         }
00318 
00319 
00320         return _VertexPtr;
00321 }
00322 
00323 
00324 // ***************************************************************************
00325 void            CVertexBufferHardGLNVidia::unlock()
00326 {
00327         // no op.
00328 }
00329 
00330 // ***************************************************************************
00331 void            CVertexBufferHardGLNVidia::unlock(uint startVert, uint endVert)
00332 {
00333         // no op.
00334         // NB: start-end only usefull for ATI ext.
00335 }
00336 
00337 // ***************************************************************************
00338 void                    CVertexBufferHardGLNVidia::enable()
00339 {
00340         if(_Driver->_CurrentVertexBufferHard != this)
00341         {
00342                 nlassert(_VertexArrayRange);
00343                 _VertexArrayRange->enable();
00344                 _Driver->_CurrentVertexBufferHard= this;
00345         }
00346 }
00347 
00348 
00349 // ***************************************************************************
00350 void                    CVertexBufferHardGLNVidia::disable()
00351 {
00352         if(_Driver->_CurrentVertexBufferHard != NULL)
00353         {
00354                 nlassert(_VertexArrayRange);
00355                 _VertexArrayRange->disable();
00356                 _Driver->_CurrentVertexBufferHard= NULL;
00357         }
00358 }
00359 
00360 
00361 // ***************************************************************************
00362 void                    CVertexBufferHardGLNVidia::setFence()
00363 {
00364         if(!isFenceSet())
00365         {
00366                 nglSetFenceNV(_Fence, GL_ALL_COMPLETED_NV);
00367                 _FenceSet= true;
00368         }
00369 }
00370 
00371 // ***************************************************************************
00372 void                    CVertexBufferHardGLNVidia::finishFence()
00373 {
00374         if(isFenceSet())
00375         {
00376                 // Stall CPU while the fence command is not reached in the GPU command stream.
00377                 nglFinishFenceNV(_Fence);
00378                 _FenceSet= false;
00379         }
00380 }
00381 
00382 
00383 
00384 // ***************************************************************************
00385 // ***************************************************************************
00386 // ***************************************************************************
00387 //
00388 // ATI implementation
00389 //
00390 // ***************************************************************************
00391 // ***************************************************************************
00392 // ***************************************************************************
00393 
00394 
00395 // ***************************************************************************
00396 // CVertexArrayRangeATI
00397 // ***************************************************************************
00398 
00399 
00400 // ***************************************************************************
00401 CVertexArrayRangeATI::CVertexArrayRangeATI(CDriverGL *drv) : IVertexArrayRange(drv)
00402 {
00403         _Allocated= false;
00404         _VertexObjectId= 0;
00405         _VertexArraySize= 0;
00406 }
00407 // ***************************************************************************
00408 bool                                    CVertexArrayRangeATI::allocate(uint32 size, IDriver::TVBHardType vbType)
00409 {
00410         nlassert(!_Allocated);
00411 
00412         // try to allocate AGP (suppose mean ATI dynamic) or VRAM (suppose mean ATI static) data.
00413         switch(vbType)
00414         {
00415         case IDriver::VBHardAGP: 
00416                 _VertexObjectId= nglNewObjectBufferATI(size, NULL, GL_DYNAMIC_ATI);
00417                 break;
00418         case IDriver::VBHardVRAM:
00419                 _VertexObjectId= nglNewObjectBufferATI(size, NULL, GL_STATIC_ATI);
00420                 break;
00421         };
00422 
00423 
00424         // init the allocator, if success
00425         if( nglIsObjectBufferATI(_VertexObjectId) )
00426         {
00427                 _Allocated= true;
00428                 /* Init with an alignment of 8. Not sure if it is usefull.
00429                         Init With a FAKE memory starting at NL3D_DRV_ATI_FAKE_MEM_START
00430                 */
00431                 _HeapMemory.initHeap((void*)NL3D_DRV_ATI_FAKE_MEM_START, size, 8);
00432 
00433                 // set the size
00434                 _VertexArraySize= size;
00435 
00436                 // Ok!
00437                 return true;
00438         }
00439         else
00440         {
00441                 // failure.
00442                 return false;
00443         }
00444 }
00445 // ***************************************************************************
00446 uint                                    CVertexArrayRangeATI::sizeAllocated() const
00447 {
00448         return _VertexArraySize;
00449 }
00450 // ***************************************************************************
00451 void                                    CVertexArrayRangeATI::free()
00452 {
00453         // release the ptr.
00454         if(_Allocated)
00455         {
00456                 // reset the allocator.
00457                 _HeapMemory.reset();
00458 
00459                 // Free special memory.
00460                 nglDeleteObjectBufferATI(_VertexObjectId);
00461 
00462                 _Allocated= false;
00463                 _VertexArraySize= 0;
00464         }
00465 }
00466 // ***************************************************************************
00467 IVertexBufferHardGL             *CVertexArrayRangeATI::createVBHardGL(uint16 vertexFormat, const uint8 *typeArray, uint32 numVertices)
00468 {
00469         // create a ATI VBHard
00470         CVertexBufferHardGLATI  *newVbHard= new CVertexBufferHardGLATI(_Driver);
00471 
00472         // Init the format of the VB.
00473         newVbHard->initFormat(vertexFormat, typeArray, numVertices);
00474 
00475         // compute size to allocate.
00476         uint32  size= newVbHard->getVertexSize() * newVbHard->getNumVertices();
00477 
00478         // try to allocate
00479         void    *vertexPtr =NULL;
00480         if( _Allocated )
00481         {
00482                  vertexPtr= allocateVB(size);
00483         }
00484 
00485         // If allocation fails.
00486         if( !vertexPtr )
00487         {
00488                 // just destroy this object (no free()).
00489                 delete newVbHard;
00490                 return NULL;
00491         }
00492         else
00493         {
00494                 // Then try to create a RAM mirror in the VB.
00495                 if( newVbHard->createRAMMirror(size) )
00496                 {
00497                         // Ok, setup
00498                         newVbHard->initGL(this, vertexPtr);
00499                         return newVbHard;
00500                 }
00501                 else
00502                 {
00503                         // Discard the VB.
00504                         delete newVbHard;
00505                         return NULL;
00506                 }
00507         }
00508 }
00509 // ***************************************************************************
00510 void                    CVertexArrayRangeATI::enable()
00511 {
00512         // No-op for ATI !!!
00513         _Driver->_CurrentVertexArrayRange= this;
00514 }
00515 // ***************************************************************************
00516 void                    CVertexArrayRangeATI::disable()
00517 {
00518         // No-op for ATI !!!
00519         _Driver->_CurrentVertexArrayRange= NULL;
00520 }
00521 // ***************************************************************************
00522 void                    *CVertexArrayRangeATI::allocateVB(uint32 size)
00523 {
00524         return _HeapMemory.allocate(size);
00525 }
00526 // ***************************************************************************
00527 void                    CVertexArrayRangeATI::freeVB(void       *ptr)
00528 {
00529         _HeapMemory.free(ptr);
00530 }
00531 
00532 
00533 // ***************************************************************************
00534 // CVertexBufferHardGLATI
00535 // ***************************************************************************
00536 
00537 
00538 // ***************************************************************************
00539 CVertexBufferHardGLATI::CVertexBufferHardGLATI(CDriverGL *drv) : IVertexBufferHardGL(drv)
00540 {
00541         _VertexArrayRange= NULL;
00542         _VertexPtr= NULL;
00543         _RAMMirrorVertexPtr= NULL;
00544         _RAMMirrorVertexSize= 0;
00545 
00546         // Flag our type
00547         ATIVertexBufferHard= true;
00548 }
00549 
00550 
00551 // ***************************************************************************
00552 CVertexBufferHardGLATI::~CVertexBufferHardGLATI()
00553 {
00554         if(_VertexArrayRange)
00555         {
00556                 // free the VAR.
00557                 _VertexArrayRange->freeVB(_VertexPtr);
00558                 _VertexPtr= NULL;
00559                 _VertexArrayRange= NULL;
00560         }
00561 
00562         if(_RAMMirrorVertexPtr)
00563         {
00564                 delete [] ((uint8*)_RAMMirrorVertexPtr);
00565                 _RAMMirrorVertexPtr= NULL;
00566                 _RAMMirrorVertexSize= 0;
00567         }
00568 }
00569 
00570 
00571 // ***************************************************************************
00572 bool            CVertexBufferHardGLATI::createRAMMirror(uint memSize)
00573 {
00574         // delete old if any
00575         if(_RAMMirrorVertexPtr)
00576         {
00577                 free(_RAMMirrorVertexPtr);
00578                 _RAMMirrorVertexPtr= NULL;
00579                 _RAMMirrorVertexSize= 0;
00580         }
00581         // create
00582         _RAMMirrorVertexPtr = (void*)new uint8[memSize];
00583         if(_RAMMirrorVertexPtr)
00584         {
00585                 _RAMMirrorVertexSize= memSize;
00586                 return true;
00587         }
00588         else
00589                 return false;
00590 }
00591 
00592 
00593 // ***************************************************************************
00594 void            CVertexBufferHardGLATI::initGL(CVertexArrayRangeATI *var, void *vertexPtr)
00595 {
00596         _VertexArrayRange= var;
00597         _VertexPtr= vertexPtr;
00598 }
00599 
00600 
00601 // ***************************************************************************
00602 void            *CVertexBufferHardGLATI::lock()
00603 {
00604         // return directly the mirror one. => client will write into RAM.
00605         return _RAMMirrorVertexPtr;
00606 }
00607 
00608 
00609 // ***************************************************************************
00610 void            CVertexBufferHardGLATI::unlock()
00611 {
00612         // Copy All mirror into the ATI Vertex Object
00613         nglUpdateObjectBufferATI(getATIVertexObjectId(), (uint)_VertexPtr - NL3D_DRV_ATI_FAKE_MEM_START,
00614                 _RAMMirrorVertexSize, _RAMMirrorVertexPtr, GL_PRESERVE_ATI);
00615 }
00616 
00617 
00618 // ***************************************************************************
00619 void            CVertexBufferHardGLATI::unlock(uint startVert, uint endVert)
00620 {
00621         // clamp endVert.
00622         if(endVert>getNumVertices())
00623                 endVert=getNumVertices();
00624 
00625         // verify bound.
00626         if(startVert>=endVert)
00627                 return;
00628 
00629         // Copy a subset of the mirror into the ATI Vertex Object
00630         uint    size= (endVert-startVert)*getVertexSize();
00631         uint    srcOffStart= startVert*getVertexSize();
00632         uint    dstOffStart= ((uint)_VertexPtr - NL3D_DRV_ATI_FAKE_MEM_START) + srcOffStart;
00633         // copy.
00634         nglUpdateObjectBufferATI(getATIVertexObjectId(), dstOffStart,
00635                 size, (uint8*)_RAMMirrorVertexPtr + srcOffStart, GL_PRESERVE_ATI);
00636 }
00637 
00638 
00639 // ***************************************************************************
00640 void                    CVertexBufferHardGLATI::enable()
00641 {
00642         if(_Driver->_CurrentVertexBufferHard != this)
00643         {
00644                 nlassert(_VertexArrayRange);
00645                 _VertexArrayRange->enable();
00646                 _Driver->_CurrentVertexBufferHard= this;
00647         }
00648 }
00649 
00650 
00651 // ***************************************************************************
00652 void                    CVertexBufferHardGLATI::disable()
00653 {
00654         if(_Driver->_CurrentVertexBufferHard != NULL)
00655         {
00656                 nlassert(_VertexArrayRange);
00657                 _VertexArrayRange->disable();
00658                 _Driver->_CurrentVertexBufferHard= NULL;
00659         }
00660 }
00661 
00662 
00663 }
00664