llvertexbuffer.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include <boost/static_assert.hpp>
00035 
00036 #include "llvertexbuffer.h"
00037 // #include "llrender.h"
00038 #include "llglheaders.h"
00039 #include "llmemory.h"
00040 #include "llmemtype.h"
00041 #include "llglimmediate.h"
00042 
00043 //============================================================================
00044 
00045 //static
00046 LLVBOPool LLVertexBuffer::sStreamVBOPool;
00047 LLVBOPool LLVertexBuffer::sDynamicVBOPool;
00048 LLVBOPool LLVertexBuffer::sStreamIBOPool;
00049 LLVBOPool LLVertexBuffer::sDynamicIBOPool;
00050 
00051 U32 LLVertexBuffer::sBindCount = 0;
00052 U32 LLVertexBuffer::sSetCount = 0;
00053 S32 LLVertexBuffer::sCount = 0;
00054 S32 LLVertexBuffer::sGLCount = 0;
00055 S32 LLVertexBuffer::sMappedCount = 0;
00056 BOOL LLVertexBuffer::sEnableVBOs = TRUE;
00057 U32 LLVertexBuffer::sGLRenderBuffer = 0;
00058 U32 LLVertexBuffer::sGLRenderIndices = 0;
00059 U32 LLVertexBuffer::sLastMask = 0;
00060 BOOL LLVertexBuffer::sVBOActive = FALSE;
00061 BOOL LLVertexBuffer::sIBOActive = FALSE;
00062 U32 LLVertexBuffer::sAllocatedBytes = 0;
00063 BOOL LLVertexBuffer::sMapped = FALSE;
00064 
00065 std::vector<U32> LLVertexBuffer::sDeleteList;
00066 
00067 S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
00068 {
00069         sizeof(LLVector3), // TYPE_VERTEX,
00070         sizeof(LLVector3), // TYPE_NORMAL,
00071         sizeof(LLVector2), // TYPE_TEXCOORD,
00072         sizeof(LLVector2), // TYPE_TEXCOORD2,
00073         sizeof(LLColor4U), // TYPE_COLOR,
00074         sizeof(LLVector3), // TYPE_BINORMAL,
00075         sizeof(F32),       // TYPE_WEIGHT,
00076         sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
00077 };
00078 
00079 U32 LLVertexBuffer::sGLMode[LLVertexBuffer::NUM_MODES] = 
00080 {
00081         GL_TRIANGLES,
00082         GL_TRIANGLE_STRIP,
00083         GL_TRIANGLE_FAN,
00084         GL_POINTS,
00085         GL_LINES,
00086         GL_LINE_STRIP,
00087         GL_QUADS,
00088         GL_LINE_LOOP,
00089 };
00090 
00091 //static
00092 void LLVertexBuffer::setupClientArrays(U32 data_mask)
00093 {
00094         /*if (LLGLImmediate::sStarted)
00095         {
00096                 llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl;
00097         }*/
00098 
00099         if (sLastMask != data_mask)
00100         {
00101                 U32 mask[] =
00102                 {
00103                         MAP_VERTEX,
00104                         MAP_NORMAL,
00105                         MAP_TEXCOORD,
00106                         MAP_COLOR
00107                 };
00108                 
00109                 GLenum array[] =
00110                 {
00111                         GL_VERTEX_ARRAY,
00112                         GL_NORMAL_ARRAY,
00113                         GL_TEXTURE_COORD_ARRAY,
00114                         GL_COLOR_ARRAY
00115                 };
00116 
00117                 for (U32 i = 0; i < 4; ++i)
00118                 {
00119                         if (sLastMask & mask[i])
00120                         { //was enabled
00121                                 if (!(data_mask & mask[i]) && i > 0)
00122                                 { //needs to be disabled
00123                                         glDisableClientState(array[i]);
00124                                 }
00125                                 else
00126                                 { //needs to be enabled, make sure it was (DEBUG TEMPORARY)
00127                                         if (i > 0 && !glIsEnabled(array[i]))
00128                                         {
00129                                                 llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
00130                                         }
00131                                 }
00132                         }
00133                         else 
00134                         {       //was disabled
00135                                 if (data_mask & mask[i])
00136                                 { //needs to be enabled
00137                                         glEnableClientState(array[i]);
00138                                 }
00139                                 else if (glIsEnabled(array[i]))
00140                                 { //needs to be disabled, make sure it was (DEBUG TEMPORARY)
00141                                         llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
00142                                 }
00143                         }
00144                 }
00145 
00146                 if (sLastMask & MAP_TEXCOORD2)
00147                 {
00148                         if (!(data_mask & MAP_TEXCOORD2))
00149                         {
00150                                 glClientActiveTextureARB(GL_TEXTURE1_ARB);
00151                                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
00152                                 glClientActiveTextureARB(GL_TEXTURE0_ARB);
00153                         }
00154                 }
00155                 else if (data_mask & MAP_TEXCOORD2)
00156                 {
00157                         glClientActiveTextureARB(GL_TEXTURE1_ARB);
00158                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00159                         glClientActiveTextureARB(GL_TEXTURE0_ARB);
00160                 }
00161 
00162                 sLastMask = data_mask;
00163         }
00164 }
00165 
00166 void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
00167 {
00168         if (start >= (U32) mRequestedNumVerts ||
00169                 end >= (U32) mRequestedNumVerts)
00170         {
00171                 llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "]" << llendl;
00172         }
00173 
00174         if (indices_offset >= (U32) mRequestedNumIndices ||
00175                 indices_offset + count > (U32) mRequestedNumIndices)
00176         {
00177                 llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
00178         }
00179 
00180         if (mGLIndices != sGLRenderIndices)
00181         {
00182                 llerrs << "Wrong index buffer bound." << llendl;
00183         }
00184 
00185         if (mGLBuffer != sGLRenderBuffer)
00186         {
00187                 llerrs << "Wrong vertex buffer bound." << llendl;
00188         }
00189 
00190         if (mode > NUM_MODES)
00191         {
00192                 llerrs << "Invalid draw mode: " << mode << llendl;
00193         }
00194 
00195         glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
00196                 ((U16*) getIndicesPointer()) + indices_offset);
00197 }
00198 
00199 void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
00200 {
00201         if (indices_offset >= (U32) mRequestedNumIndices ||
00202                 indices_offset + count > (U32) mRequestedNumIndices)
00203         {
00204                 llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
00205         }
00206 
00207         if (mGLIndices != sGLRenderIndices)
00208         {
00209                 llerrs << "Wrong index buffer bound." << llendl;
00210         }
00211 
00212         if (mGLBuffer != sGLRenderBuffer)
00213         {
00214                 llerrs << "Wrong vertex buffer bound." << llendl;
00215         }
00216 
00217         if (mode > NUM_MODES)
00218         {
00219                 llerrs << "Invalid draw mode: " << mode << llendl;
00220         }
00221 
00222         glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
00223                 ((U16*) getIndicesPointer()) + indices_offset);
00224 }
00225 
00226 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
00227 {
00228         
00229         if (first >= (U32) mRequestedNumVerts ||
00230                 first + count > (U32) mRequestedNumVerts)
00231         {
00232                 llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
00233         }
00234 
00235         if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
00236         {
00237                 llerrs << "Wrong vertex buffer bound." << llendl;
00238         }
00239 
00240         if (mode > NUM_MODES)
00241         {
00242                 llerrs << "Invalid draw mode: " << mode << llendl;
00243         }
00244 
00245         glDrawArrays(sGLMode[mode], first, count);
00246 }
00247 
00248 //static
00249 void LLVertexBuffer::initClass(bool use_vbo)
00250 {
00251         sEnableVBOs = use_vbo;
00252         LLGLNamePool::registerPool(&sDynamicVBOPool);
00253         LLGLNamePool::registerPool(&sDynamicIBOPool);
00254         LLGLNamePool::registerPool(&sStreamVBOPool);
00255         LLGLNamePool::registerPool(&sStreamIBOPool);
00256 }
00257 
00258 //static 
00259 void LLVertexBuffer::unbind()
00260 {
00261         if (sVBOActive)
00262         {
00263                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
00264                 sVBOActive = FALSE;
00265         }
00266         if (sIBOActive)
00267         {
00268                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
00269                 sIBOActive = FALSE;
00270         }
00271 
00272         sGLRenderBuffer = 0;
00273         sGLRenderIndices = 0;
00274 
00275         setupClientArrays(0);
00276 }
00277 
00278 //static
00279 void LLVertexBuffer::cleanupClass()
00280 {
00281         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00282         unbind();
00283         clientCopy(); // deletes GL buffers
00284 }
00285 
00286 void LLVertexBuffer::clientCopy(F64 max_time)
00287 {
00288         if (!sDeleteList.empty())
00289         {
00290                 glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0]));
00291                 sDeleteList.clear();
00292         }
00293 }
00294 
00295 //----------------------------------------------------------------------------
00296 
00297 LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
00298         LLRefCount(),
00299         mNumVerts(0), mNumIndices(0), mUsage(usage), mGLBuffer(0), mGLIndices(0), 
00300         mMappedData(NULL),
00301         mMappedIndexData(NULL), mLocked(FALSE),
00302         mFinal(FALSE),
00303         mFilthy(FALSE),
00304         mEmpty(TRUE),
00305         mResized(FALSE),
00306         mDynamicSize(FALSE)
00307 {
00308         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00309         if (!sEnableVBOs)
00310         {
00311                 mUsage = 0 ; 
00312         }
00313         
00314         S32 stride = calcStride(typemask, mOffsets);
00315 
00316         mTypeMask = typemask;
00317         mStride = stride;
00318         sCount++;
00319 }
00320 
00321 //static
00322 S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
00323 {
00324         S32 stride = 0;
00325         for (S32 i=0; i<TYPE_MAX; i++)
00326         {
00327                 U32 mask = 1<<i;
00328                 if (typemask & mask)
00329                 {
00330                         if (offsets)
00331                         {
00332                                 offsets[i] = stride;
00333                         }
00334                         stride += sTypeOffsets[i];
00335                 }
00336         }
00337 
00338         return stride;
00339 }
00340 
00341 // protected, use unref()
00342 //virtual
00343 LLVertexBuffer::~LLVertexBuffer()
00344 {
00345         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00346         destroyGLBuffer();
00347         destroyGLIndices();
00348         sCount--;
00349 };
00350 
00351 //----------------------------------------------------------------------------
00352 
00353 void LLVertexBuffer::genBuffer()
00354 {
00355         if (mUsage == GL_STREAM_DRAW_ARB)
00356         {
00357                 mGLBuffer = sStreamVBOPool.allocate();
00358         }
00359         else if (mUsage == GL_DYNAMIC_DRAW_ARB)
00360         {
00361                 mGLBuffer = sDynamicVBOPool.allocate();
00362         }
00363         else
00364         {
00365                 BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
00366                 glGenBuffersARB(1, (GLuint*)&mGLBuffer);
00367         }
00368         sGLCount++;
00369 }
00370 
00371 void LLVertexBuffer::genIndices()
00372 {
00373         if (mUsage == GL_STREAM_DRAW_ARB)
00374         {
00375                 mGLIndices = sStreamIBOPool.allocate();
00376         }
00377         else if (mUsage == GL_DYNAMIC_DRAW_ARB)
00378         {
00379                 mGLIndices = sDynamicIBOPool.allocate();
00380         }
00381         else
00382         {
00383                 BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
00384                 glGenBuffersARB(1, (GLuint*)&mGLIndices);
00385         }
00386         sGLCount++;
00387 }
00388 
00389 void LLVertexBuffer::releaseBuffer()
00390 {
00391         if (mUsage == GL_STREAM_DRAW_ARB)
00392         {
00393                 sStreamVBOPool.release(mGLBuffer);
00394         }
00395         else if (mUsage == GL_DYNAMIC_DRAW_ARB)
00396         {
00397                 sDynamicVBOPool.release(mGLBuffer);
00398         }
00399         else
00400         {
00401                 sDeleteList.push_back(mGLBuffer);
00402         }
00403         sGLCount--;
00404 }
00405 
00406 void LLVertexBuffer::releaseIndices()
00407 {
00408         if (mUsage == GL_STREAM_DRAW_ARB)
00409         {
00410                 sStreamIBOPool.release(mGLIndices);
00411         }
00412         else if (mUsage == GL_DYNAMIC_DRAW_ARB)
00413         {
00414                 sDynamicIBOPool.release(mGLIndices);
00415         }
00416         else
00417         {
00418                 sDeleteList.push_back(mGLIndices);
00419         }
00420         sGLCount--;
00421 }
00422 
00423 void LLVertexBuffer::createGLBuffer()
00424 {
00425         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00426 
00427         U32 size = getSize();
00428         if (mGLBuffer)
00429         {
00430                 destroyGLBuffer();
00431         }
00432 
00433         if (size == 0)
00434         {
00435                 return;
00436         }
00437 
00438         mEmpty = TRUE;
00439 
00440         if (useVBOs())
00441         {
00442                 mMappedData = NULL;
00443                 genBuffer();
00444                 mResized = TRUE;
00445         }
00446         else
00447         {
00448                 static int gl_buffer_idx = 0;
00449                 mGLBuffer = ++gl_buffer_idx;
00450                 mMappedData = new U8[size];
00451                 memset(mMappedData, 0, size);
00452         }
00453 }
00454 
00455 void LLVertexBuffer::createGLIndices()
00456 {
00457         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00458         U32 size = getIndicesSize();
00459 
00460         if (mGLIndices)
00461         {
00462                 destroyGLIndices();
00463         }
00464         
00465         if (size == 0)
00466         {
00467                 return;
00468         }
00469 
00470         mEmpty = TRUE;
00471 
00472         if (useVBOs())
00473         {
00474                 mMappedIndexData = NULL;
00475                 genIndices();
00476                 mResized = TRUE;
00477         }
00478         else
00479         {
00480                 mMappedIndexData = new U8[size];
00481                 memset(mMappedIndexData, 0, size);
00482                 static int gl_buffer_idx = 0;
00483                 mGLIndices = ++gl_buffer_idx;
00484         }
00485 }
00486 
00487 void LLVertexBuffer::destroyGLBuffer()
00488 {
00489         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00490         if (mGLBuffer)
00491         {
00492                 if (useVBOs())
00493                 {
00494                         if (mMappedData || mMappedIndexData)
00495                         {
00496                                 llerrs << "Vertex buffer destroyed while mapped!" << llendl;
00497                         }
00498                         releaseBuffer();
00499                 }
00500                 else
00501                 {
00502                         delete [] mMappedData;
00503                         mMappedData = NULL;
00504                         mEmpty = TRUE;
00505                 }
00506 
00507                 sAllocatedBytes -= getSize();
00508         }
00509         
00510         mGLBuffer = 0;
00511         unbind();
00512 }
00513 
00514 void LLVertexBuffer::destroyGLIndices()
00515 {
00516         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00517         if (mGLIndices)
00518         {
00519                 if (useVBOs())
00520                 {
00521                         if (mMappedData || mMappedIndexData)
00522                         {
00523                                 llerrs << "Vertex buffer destroyed while mapped." << llendl;
00524                         }
00525                         releaseIndices();
00526                 }
00527                 else
00528                 {
00529                         delete [] mMappedIndexData;
00530                         mMappedIndexData = NULL;
00531                         mEmpty = TRUE;
00532                 }
00533 
00534                 sAllocatedBytes -= getIndicesSize();
00535         }
00536 
00537         mGLIndices = 0;
00538         unbind();
00539 }
00540 
00541 void LLVertexBuffer::updateNumVerts(S32 nverts)
00542 {
00543         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00544 
00545         if (nverts >= 65535)
00546         {
00547                 llwarns << "Vertex buffer overflow!" << llendl;
00548                 nverts = 65535;
00549         }
00550 
00551         mRequestedNumVerts = nverts;
00552         
00553         if (!mDynamicSize)
00554         {
00555                 mNumVerts = nverts;
00556         }
00557         else if (mUsage == GL_STATIC_DRAW_ARB ||
00558                 nverts > mNumVerts ||
00559                 nverts < mNumVerts/2)
00560         {
00561                 if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535)
00562                 {
00563                         nverts += nverts/4;
00564                 }
00565                 mNumVerts = nverts;
00566         }
00567 
00568 }
00569 
00570 void LLVertexBuffer::updateNumIndices(S32 nindices)
00571 {
00572         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00573         mRequestedNumIndices = nindices;
00574         if (!mDynamicSize)
00575         {
00576                 mNumIndices = nindices;
00577         }
00578         else if (mUsage == GL_STATIC_DRAW_ARB ||
00579                 nindices > mNumIndices ||
00580                 nindices < mNumIndices/2)
00581         {
00582                 if (mUsage != GL_STATIC_DRAW_ARB)
00583                 {
00584                         nindices += nindices/4;
00585                 }
00586 
00587                 mNumIndices = nindices;
00588         }
00589 }
00590 
00591 void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
00592 {
00593         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00594                 
00595         updateNumVerts(nverts);
00596         updateNumIndices(nindices);
00597         
00598         if (mMappedData)
00599         {
00600                 llerrs << "LLVertexBuffer::allocateBuffer() called redundantly." << llendl;
00601         }
00602         if (create && (nverts || nindices))
00603         {
00604                 createGLBuffer();
00605                 createGLIndices();
00606         }
00607         
00608         sAllocatedBytes += getSize() + getIndicesSize();
00609 }
00610 
00611 void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
00612 {
00613         mRequestedNumVerts = newnverts;
00614         mRequestedNumIndices = newnindices;
00615 
00616         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00617         mDynamicSize = TRUE;
00618         if (mUsage == GL_STATIC_DRAW_ARB)
00619         { //always delete/allocate static buffers on resize
00620                 destroyGLBuffer();
00621                 destroyGLIndices();
00622                 allocateBuffer(newnverts, newnindices, TRUE);
00623                 mFinal = FALSE;
00624         }
00625         else if (newnverts > mNumVerts || newnindices > mNumIndices ||
00626                          newnverts < mNumVerts/2 || newnindices < mNumIndices/2)
00627         {
00628                 sAllocatedBytes -= getSize() + getIndicesSize();
00629                 
00630                 S32 oldsize = getSize();
00631                 S32 old_index_size = getIndicesSize();
00632 
00633                 updateNumVerts(newnverts);              
00634                 updateNumIndices(newnindices);
00635                 
00636                 S32 newsize = getSize();
00637                 S32 new_index_size = getIndicesSize();
00638 
00639                 sAllocatedBytes += newsize + new_index_size;
00640 
00641                 if (newsize)
00642                 {
00643                         if (!mGLBuffer)
00644                         { //no buffer exists, create a new one
00645                                 createGLBuffer();
00646                         }
00647                         else
00648                         {
00649                                 //delete old buffer, keep GL buffer for now
00650                                 if (!useVBOs())
00651                                 {
00652                                         U8* old = mMappedData;
00653                                         mMappedData = new U8[newsize];
00654                                         if (old)
00655                                         {       
00656                                                 memcpy(mMappedData, old, llmin(newsize, oldsize));
00657                                                 if (newsize > oldsize)
00658                                                 {
00659                                                         memset(mMappedData+oldsize, 0, newsize-oldsize);
00660                                                 }
00661 
00662                                                 delete [] old;
00663                                         }
00664                                         else
00665                                         {
00666                                                 memset(mMappedData, 0, newsize);
00667                                                 mEmpty = TRUE;
00668                                         }
00669                                 }
00670                                 mResized = TRUE;
00671                         }
00672                 }
00673                 else if (mGLBuffer)
00674                 {
00675                         destroyGLBuffer();
00676                 }
00677                 
00678                 if (new_index_size)
00679                 {
00680                         if (!mGLIndices)
00681                         {
00682                                 createGLIndices();
00683                         }
00684                         else
00685                         {
00686                                 if (!useVBOs())
00687                                 {
00688                                         //delete old buffer, keep GL buffer for now
00689                                         U8* old = mMappedIndexData;
00690                                         mMappedIndexData = new U8[new_index_size];
00691                                         
00692                                         if (old)
00693                                         {       
00694                                                 memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
00695                                                 if (new_index_size > old_index_size)
00696                                                 {
00697                                                         memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
00698                                                 }
00699                                                 delete [] old;
00700                                         }
00701                                         else
00702                                         {
00703                                                 memset(mMappedIndexData, 0, new_index_size);
00704                                                 mEmpty = TRUE;
00705                                         }
00706                                 }
00707                                 mResized = TRUE;
00708                         }
00709                 }
00710                 else if (mGLIndices)
00711                 {
00712                         destroyGLIndices();
00713                 }
00714         }
00715 
00716         if (mResized && useVBOs())
00717         {
00718                 setBuffer(0);
00719         }
00720 }
00721 
00722 BOOL LLVertexBuffer::useVBOs() const
00723 {
00724         //it's generally ineffective to use VBO for things that are streaming on apple
00725                 
00726 #if LL_DARWIN
00727         if (!mUsage || mUsage == GL_STREAM_DRAW_ARB)
00728         {
00729                 return FALSE;
00730         }
00731 #else
00732         if (!mUsage)
00733         {
00734                 return FALSE;
00735         }
00736 #endif
00737         return sEnableVBOs;
00738 }
00739 
00740 //----------------------------------------------------------------------------
00741 
00742 // Map for data access
00743 U8* LLVertexBuffer::mapBuffer(S32 access)
00744 {
00745         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00746         if (mFinal)
00747         {
00748                 llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl;
00749         }
00750         if (!useVBOs() && !mMappedData && !mMappedIndexData)
00751         {
00752                 llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl;
00753         }
00754                 
00755         if (!mLocked && useVBOs())
00756         {
00757                 setBuffer(0);
00758                 mLocked = TRUE;
00759                 stop_glerror();
00760                 mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
00761                 stop_glerror();
00762                 mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
00763                 stop_glerror();
00764                 /*if (sMapped)
00765                 {
00766                         llerrs << "Mapped two VBOs at the same time!" << llendl;
00767                 }
00768                 sMapped = TRUE;*/
00769                 if (!mMappedData)
00770                 {
00771                         llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
00772                 }
00773 
00774                 if (!mMappedIndexData)
00775                 {
00776                         llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
00777                 }
00778 
00779                 sMappedCount++;
00780         }
00781         
00782         return mMappedData;
00783 }
00784 
00785 void LLVertexBuffer::unmapBuffer()
00786 {
00787         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00788         if (mMappedData || mMappedIndexData)
00789         {
00790                 if (useVBOs() && mLocked)
00791                 {
00792                         stop_glerror();
00793                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
00794                         stop_glerror();
00795                         glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
00796                         stop_glerror();
00797 
00798                         /*if (!sMapped)
00799                         {
00800                                 llerrs << "Redundantly unmapped VBO!" << llendl;
00801                         }
00802                         sMapped = FALSE;*/
00803                         sMappedCount--;
00804 
00805                         if (mUsage == GL_STATIC_DRAW_ARB)
00806                         { //static draw buffers can only be mapped a single time
00807                                 //throw out client data (we won't be using it again)
00808                                 mEmpty = TRUE;
00809                                 mFinal = TRUE;
00810                         }
00811                         else
00812                         {
00813                                 mEmpty = FALSE;
00814                         }
00815 
00816                         mMappedIndexData = NULL;
00817                         mMappedData = NULL;
00818                         
00819                         mLocked = FALSE;
00820                 }
00821         }
00822 }
00823 
00824 //----------------------------------------------------------------------------
00825 
00826 template <class T,S32 type> struct VertexBufferStrider
00827 {
00828         typedef LLStrider<T> strider_t;
00829         static bool get(LLVertexBuffer& vbo, 
00830                                         strider_t& strider, 
00831                                         S32 index)
00832         {
00833                 if (vbo.mapBuffer() == NULL)
00834                 {
00835                         llwarns << "mapBuffer failed!" << llendl;
00836                         return FALSE;
00837                 }
00838 
00839                 if (type == LLVertexBuffer::TYPE_INDEX)
00840                 {
00841                         S32 stride = sizeof(T);
00842                         strider = (T*)(vbo.getMappedIndices() + index*stride);
00843                         strider.setStride(0);
00844                         return TRUE;
00845                 }
00846                 else if (vbo.hasDataType(type))
00847                 {
00848                         S32 stride = vbo.getStride();
00849                         strider = (T*)(vbo.getMappedData() + vbo.getOffset(type) + index*stride);
00850                         strider.setStride(stride);
00851                         return TRUE;
00852                 }
00853                 else
00854                 {
00855                         llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
00856                 }
00857                 return FALSE;
00858         }
00859 };
00860 
00861 
00862 bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index)
00863 {
00864         return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index);
00865 }
00866 bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index)
00867 {
00868         return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index);
00869 }
00870 bool LLVertexBuffer::getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index)
00871 {
00872         return VertexBufferStrider<LLVector2,TYPE_TEXCOORD>::get(*this, strider, index);
00873 }
00874 bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index)
00875 {
00876         return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index);
00877 }
00878 bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index)
00879 {
00880         return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index);
00881 }
00882 bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index)
00883 {
00884         return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index);
00885 }
00886 bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index)
00887 {
00888         return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index);
00889 }
00890 bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index)
00891 {
00892         return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index);
00893 }
00894 bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index)
00895 {
00896         return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index);
00897 }
00898 
00899 void LLVertexBuffer::setStride(S32 type, S32 new_stride)
00900 {
00901         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00902         if (mNumVerts)
00903         {
00904                 llerrs << "LLVertexBuffer::setOffset called with mNumVerts = " << mNumVerts << llendl;
00905         }
00906         // This code assumes that setStride() will only be called once per VBO per type.
00907         S32 delta = new_stride - sTypeOffsets[type];
00908         for (S32 i=type+1; i<TYPE_MAX; i++)
00909         {
00910                 if (mTypeMask & (1<<i))
00911                 {
00912                         mOffsets[i] += delta;
00913                 }
00914         }
00915         mStride += delta;
00916 }
00917 
00918 //----------------------------------------------------------------------------
00919 
00920 // Set for rendering
00921 void LLVertexBuffer::setBuffer(U32 data_mask)
00922 {
00923         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
00924         //set up pointers if the data mask is different ...
00925         BOOL setup = (sLastMask != data_mask);
00926 
00927         if (useVBOs())
00928         {
00929                 if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
00930                 {
00931                         /*if (sMapped)
00932                         {
00933                                 llerrs << "VBO bound while another VBO mapped!" << llendl;
00934                         }*/
00935                         stop_glerror();
00936                         glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
00937                         stop_glerror();
00938                         sBindCount++;
00939                         sVBOActive = TRUE;
00940                         setup = TRUE; // ... or the bound buffer changed
00941                 }
00942                 if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))
00943                 {
00944                         /*if (sMapped)
00945                         {
00946                                 llerrs << "VBO bound while another VBO mapped!" << llendl;
00947                         }*/
00948                         stop_glerror();
00949                         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
00950                         stop_glerror();
00951                         sBindCount++;
00952                         sIBOActive = TRUE;
00953                 }
00954                 
00955                 if (mResized)
00956                 {
00957                         if (gDebugGL)
00958                         {
00959                                 GLint buff;
00960                                 glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
00961                                 if (buff != mGLBuffer)
00962                                 {
00963                                         llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
00964                                 }
00965 
00966                                 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
00967                                 if (buff != mGLIndices)
00968                                 {
00969                                         llerrs << "Invalid GL index buffer bound: " << buff << llendl;
00970                                 }
00971                         }
00972 
00973                         if (mGLBuffer)
00974                         {
00975                                 stop_glerror();
00976                                 glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), NULL, mUsage);
00977                                 stop_glerror();
00978                         }
00979                         if (mGLIndices)
00980                         {
00981                                 stop_glerror();
00982                                 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), NULL, mUsage);
00983                                 stop_glerror();
00984                         }
00985 
00986                         mEmpty = TRUE;
00987                         mResized = FALSE;
00988 
00989                         if (data_mask != 0)
00990                         {
00991                                 llerrs << "Buffer set for rendering before being filled after resize." << llendl;
00992                         }
00993                 }
00994 
00995                 unmapBuffer();
00996         }
00997         else
00998         {               
00999                 if (mGLBuffer)
01000                 {
01001                         if (sEnableVBOs && sVBOActive)
01002                         {
01003                                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
01004                                 sBindCount++;
01005                                 sVBOActive = FALSE;
01006                                 setup = TRUE; // ... or a VBO is deactivated
01007                         }
01008                         if (sGLRenderBuffer != mGLBuffer)
01009                         {
01010                                 setup = TRUE; // ... or a client memory pointer changed
01011                         }
01012                 }
01013                 if (sEnableVBOs && mGLIndices && sIBOActive)
01014                 {
01015                         /*if (sMapped)
01016                         {
01017                                 llerrs << "VBO unbound while potentially mapped!" << llendl;
01018                         }*/
01019                         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
01020                         sBindCount++;
01021                         sIBOActive = FALSE;
01022                 }
01023         }
01024 
01025         setupClientArrays(data_mask);
01026         
01027         if (mGLIndices)
01028         {
01029                 sGLRenderIndices = mGLIndices;
01030         }
01031         if (mGLBuffer)
01032         {
01033                 sGLRenderBuffer = mGLBuffer;
01034                 if (data_mask && setup)
01035                 {
01036                         setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
01037                         sSetCount++;
01038                 }
01039         }
01040 }
01041 
01042 // virtual (default)
01043 void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
01044 {
01045         LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
01046         stop_glerror();
01047         U8* base = useVBOs() ? NULL : mMappedData;
01048         S32 stride = mStride;
01049 
01050         if ((data_mask & mTypeMask) != data_mask)
01051         {
01052                 llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
01053         }
01054 
01055         if (data_mask & MAP_NORMAL)
01056         {
01057                 glNormalPointer(GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_NORMAL]));
01058         }
01059         if (data_mask & MAP_TEXCOORD2)
01060         {
01061                 glClientActiveTextureARB(GL_TEXTURE1_ARB);
01062                 glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
01063                 glClientActiveTextureARB(GL_TEXTURE0_ARB);
01064         }
01065         if (data_mask & MAP_TEXCOORD)
01066         {
01067                 glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD]));
01068         }
01069         if (data_mask & MAP_COLOR)
01070         {
01071                 glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)(base + mOffsets[TYPE_COLOR]));
01072         }
01073         if (data_mask & MAP_BINORMAL)
01074         {
01075                 glVertexAttribPointerARB(6, 3, GL_FLOAT, FALSE,  stride, (void*)(base + mOffsets[TYPE_BINORMAL]));
01076         }
01077         if (data_mask & MAP_WEIGHT)
01078         {
01079                 glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT]));
01080         }
01081         if (data_mask & MAP_CLOTHWEIGHT)
01082         {
01083                 glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE,  stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
01084         }
01085         if (data_mask & MAP_VERTEX)
01086         {
01087                 glVertexPointer(3,GL_FLOAT, stride, (void*)(base + 0));
01088         }
01089 
01090         llglassertok();
01091 }
01092 
01093 void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count)
01094 {
01095         // TODO: use GL_APPLE_flush_buffer_range here
01096         /*if (useVBOs() && !mFilthy)
01097         {
01098         
01099         }*/
01100 }

Generated on Fri May 16 08:32:50 2008 for SecondLife by  doxygen 1.5.5