Newer
Older
/**
* @file llvertexbuffer.cpp
* @brief LLVertexBuffer implementation
*
* $LicenseInfo:firstyear=2003&license=viewergpl$
*
* Copyright (c) 2003-2009, Linden Research, Inc.
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
#include "linden_common.h"
#include <boost/static_assert.hpp>
#include "llvertexbuffer.h"
// #include "llrender.h"
#include "llglheaders.h"
#include "llmemtype.h"
#include "llrender.h"
//============================================================================
//static
LLVBOPool LLVertexBuffer::sStreamVBOPool;
LLVBOPool LLVertexBuffer::sDynamicVBOPool;
LLVBOPool LLVertexBuffer::sStreamIBOPool;
LLVBOPool LLVertexBuffer::sDynamicIBOPool;
U32 LLVertexBuffer::sBindCount = 0;
U32 LLVertexBuffer::sSetCount = 0;
S32 LLVertexBuffer::sCount = 0;
S32 LLVertexBuffer::sGLCount = 0;
S32 LLVertexBuffer::sMappedCount = 0;
BOOL LLVertexBuffer::sEnableVBOs = TRUE;
Josh Bell
committed
U32 LLVertexBuffer::sGLRenderBuffer = 0;
U32 LLVertexBuffer::sGLRenderIndices = 0;
U32 LLVertexBuffer::sLastMask = 0;
BOOL LLVertexBuffer::sVBOActive = FALSE;
BOOL LLVertexBuffer::sIBOActive = FALSE;
U32 LLVertexBuffer::sAllocatedBytes = 0;
BOOL LLVertexBuffer::sMapped = FALSE;
BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
std::vector<U32> LLVertexBuffer::sDeleteList;
#define LL_ALIGNED_VB 1
#if LL_ALIGNED_VB
S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
{
sizeof(LLVector4), // TYPE_VERTEX,
sizeof(LLVector4), // TYPE_NORMAL,
sizeof(LLVector2), // TYPE_TEXCOORD0,
sizeof(LLVector2), // TYPE_TEXCOORD1,
sizeof(LLVector2), // TYPE_TEXCOORD2,
sizeof(LLVector2), // TYPE_TEXCOORD3,
sizeof(LLColor4U), // TYPE_COLOR,
sizeof(LLVector4), // TYPE_BINORMAL,
sizeof(F32), // TYPE_WEIGHT,
sizeof(LLVector4), // TYPE_WEIGHT4,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
};
#else
S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
{
sizeof(LLVector3), // TYPE_VERTEX,
sizeof(LLVector3), // TYPE_NORMAL,
sizeof(LLVector2), // TYPE_TEXCOORD0,
sizeof(LLVector2), // TYPE_TEXCOORD1,
sizeof(LLVector2), // TYPE_TEXCOORD2,
sizeof(LLVector2), // TYPE_TEXCOORD3,
sizeof(LLColor4U), // TYPE_COLOR,
sizeof(LLVector3), // TYPE_BINORMAL,
sizeof(F32), // TYPE_WEIGHT,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
};
U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
{
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_QUADS,
GL_LINE_LOOP,
};
//static
void LLVertexBuffer::setupClientArrays(U32 data_mask)
{
{
llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl;
if (sLastMask != data_mask)
{
U32 mask[] =
{
MAP_VERTEX,
MAP_NORMAL,
MAP_TEXCOORD0,
MAP_COLOR,
};
GLenum array[] =
{
GL_VERTEX_ARRAY,
GL_NORMAL_ARRAY,
GL_TEXTURE_COORD_ARRAY,
GL_COLOR_ARRAY,
BOOL error = FALSE;
for (U32 i = 0; i < 4; ++i)
{
if (sLastMask & mask[i])
{ //was enabled
if (!(data_mask & mask[i]) && i > 0)
{ //needs to be disabled
glDisableClientState(array[i]);
}
else if (gDebugGL)
{ //needs to be enabled, make sure it was (DEBUG TEMPORARY)
if (i > 0 && !glIsEnabled(array[i]))
{
if (gDebugSession)
{
error = TRUE;
gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
}
else
{
llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
}
}
}
}
else
{ //was disabled
if (data_mask & mask[i])
{ //needs to be enabled
glEnableClientState(array[i]);
}
else if (gDebugGL && glIsEnabled(array[i]))
{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
if (gDebugSession)
{
error = TRUE;
gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
}
else
{
llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
}
if (error)
{
ll_fail("LLVertexBuffer::setupClientArrays failed");
}
U32 map_tc[] =
MAP_TEXCOORD1,
MAP_TEXCOORD2,
MAP_TEXCOORD3
};
for (U32 i = 0; i < 3; i++)
{
if (sLastMask & map_tc[i])
if (!(data_mask & map_tc[i]))
{
glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
else if (data_mask & map_tc[i])
{
glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
if (sLastMask & MAP_BINORMAL)
{
if (!(data_mask & MAP_BINORMAL))
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
else if (data_mask & MAP_BINORMAL)
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (sLastMask & MAP_WEIGHT4)
{
if (sWeight4Loc < 0)
{
llerrs << "Weighting disabled but vertex buffer still bound!" << llendl;
}
if (!(data_mask & MAP_WEIGHT4))
{ //disable 4-component skin weight
glDisableVertexAttribArrayARB(sWeight4Loc);
}
}
else if (data_mask & MAP_WEIGHT4)
{
if (sWeight4Loc >= 0)
{ //enable 4-component skin weight
glEnableVertexAttribArrayARB(sWeight4Loc);
}
}
sLastMask = data_mask;
}
}
void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
{
if (start >= (U32) mRequestedNumVerts ||
llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mRequestedNumVerts << llendl;
if (indices_offset >= (U32) mRequestedNumIndices ||
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
if (gDebugGL && !useVBOs())
{
U16* idx = ((U16*) getIndicesPointer())+indices_offset;
for (U32 i = 0; i < count; ++i)
{
if (idx[i] < start || idx[i] > end)
{
llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
}
}
}
}
void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
{
validateRange(start, end, count, indices_offset);
llassert(mRequestedNumVerts >= 0);
if (mGLIndices != sGLRenderIndices)
{
llerrs << "Wrong index buffer bound." << llendl;
}
if (mGLBuffer != sGLRenderBuffer)
{
llerrs << "Wrong vertex buffer bound." << llendl;
}
{
llerrs << "Invalid draw mode: " << mode << llendl;
stop_glerror();
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
}
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
if (indices_offset >= (U32) mRequestedNumIndices ||
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
if (mGLIndices != sGLRenderIndices)
{
llerrs << "Wrong index buffer bound." << llendl;
}
if (mGLBuffer != sGLRenderBuffer)
{
llerrs << "Wrong vertex buffer bound." << llendl;
}
{
llerrs << "Invalid draw mode: " << mode << llendl;
stop_glerror();
glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
((U16*) getIndicesPointer()) + indices_offset);
stop_glerror();
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{
{
llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
}
if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
{
llerrs << "Wrong vertex buffer bound." << llendl;
}
{
llerrs << "Invalid draw mode: " << mode << llendl;
stop_glerror();
glDrawArrays(sGLMode[mode], first, count);
//static
void LLVertexBuffer::initClass(bool use_vbo)
{
sEnableVBOs = use_vbo;
LLGLNamePool::registerPool(&sDynamicVBOPool);
LLGLNamePool::registerPool(&sDynamicIBOPool);
LLGLNamePool::registerPool(&sStreamVBOPool);
LLGLNamePool::registerPool(&sStreamIBOPool);
}
//static
void LLVertexBuffer::unbind()
{
if (sVBOActive)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
sVBOActive = FALSE;
}
if (sIBOActive)
{
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
sIBOActive = FALSE;
}
sGLRenderBuffer = 0;
sGLRenderIndices = 0;
}
//static
void LLVertexBuffer::cleanupClass()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
Josh Bell
committed
void LLVertexBuffer::clientCopy(F64 max_time)
{
if (!sDeleteList.empty())
{
glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0]));
sDeleteList.clear();
}
}
//----------------------------------------------------------------------------
LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
LLRefCount(),
mNumVerts(0),
mNumIndices(0),
mRequestedNumVerts(-1),
mRequestedNumIndices(-1),
mUsage(usage),
mGLBuffer(0),
mGLIndices(0),
mMappedData(NULL),
mMappedIndexData(NULL), mLocked(FALSE),
Josh Bell
committed
mFinal(FALSE),
mFilthy(FALSE),
mEmpty(TRUE),
mResized(FALSE),
mDynamicSize(FALSE)
LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
if (!sEnableVBOs)
{
mUsage = 0 ;
if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
{
mUsage = 0;
if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
{
mUsage = 0;
S32 stride = calcStride(typemask, mOffsets);
mTypeMask = typemask;
mStride = stride;
sCount++;
}
//static
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets, S32 num_vertices)
{
S32 offset = 0;
for (S32 i=0; i<TYPE_MAX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
{
if (offsets)
{
offsets[i] = offset;
offset += LLVertexBuffer::sTypeOffsets[i]*num_vertices;
offset = (offset + 0xF) & ~0xF;
}
}
}
return offset+16;
}
S32 LLVertexBuffer::getSize() const
{
return mStride;
}
#else
//static
S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets, S32 num_vertices)
{
S32 stride = 0;
for (S32 i=0; i<TYPE_MAX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
{
if (offsets)
{
offsets[i] = stride;
}
stride += sTypeOffsets[i];
}
}
return stride;
S32 LLVertexBuffer::getSize() const
{
return mNumVerts*mStride;
}
#endif
// protected, use unref()
//virtual
LLVertexBuffer::~LLVertexBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
destroyGLBuffer();
destroyGLIndices();
sCount--;
};
//----------------------------------------------------------------------------
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
void LLVertexBuffer::genBuffer()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
mGLBuffer = sStreamVBOPool.allocate();
}
else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
mGLBuffer = sDynamicVBOPool.allocate();
}
else
{
BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
glGenBuffersARB(1, (GLuint*)&mGLBuffer);
}
sGLCount++;
}
void LLVertexBuffer::genIndices()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
mGLIndices = sStreamIBOPool.allocate();
}
else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
mGLIndices = sDynamicIBOPool.allocate();
}
else
{
BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
glGenBuffersARB(1, (GLuint*)&mGLIndices);
}
sGLCount++;
}
void LLVertexBuffer::releaseBuffer()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
sStreamVBOPool.release(mGLBuffer);
}
else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
sDynamicVBOPool.release(mGLBuffer);
}
else
{
sDeleteList.push_back(mGLBuffer);
}
sGLCount--;
}
void LLVertexBuffer::releaseIndices()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
sStreamIBOPool.release(mGLIndices);
}
else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
sDynamicIBOPool.release(mGLIndices);
}
else
{
sDeleteList.push_back(mGLIndices);
}
sGLCount--;
}
void LLVertexBuffer::createGLBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES);
U32 size = getSize();
if (mGLBuffer)
{
destroyGLBuffer();
}
if (size == 0)
{
return;
}
mEmpty = TRUE;
if (useVBOs())
{
mMappedData = NULL;
genBuffer();
mResized = TRUE;
}
else
{
static int gl_buffer_idx = 0;
mGLBuffer = ++gl_buffer_idx;
mMappedData = (U8*) ll_aligned_malloc_16(size);
memset(mMappedData, 0, size);
}
}
void LLVertexBuffer::createGLIndices()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES);
U32 size = getIndicesSize();
if (mGLIndices)
{
destroyGLIndices();
}
if (size == 0)
{
return;
}
mEmpty = TRUE;
//pad by 16 bytes for aligned copies
size += 16;
//pad by another 16 bytes for VBO pointer adjustment
size += 16;
mMappedIndexData = NULL;
genIndices();
mResized = TRUE;
}
else
{
mMappedIndexData = (U8*) ll_aligned_malloc_16(size);
static int gl_buffer_idx = 0;
mGLIndices = ++gl_buffer_idx;
}
}
void LLVertexBuffer::destroyGLBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER);
if (mGLBuffer)
{
if (useVBOs())
{
if (mMappedData || mMappedIndexData)
{
llerrs << "Vertex buffer destroyed while mapped!" << llendl;
}
releaseBuffer();
}
else
{
ll_aligned_free_16(mMappedData);
mMappedData = NULL;
mEmpty = TRUE;
sAllocatedBytes -= getSize();
}
mGLBuffer = 0;
//unbind();
}
void LLVertexBuffer::destroyGLIndices()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES);
if (mGLIndices)
{
if (useVBOs())
{
if (mMappedData || mMappedIndexData)
{
llerrs << "Vertex buffer destroyed while mapped." << llendl;
}
releaseIndices();
}
else
{
ll_aligned_free_16(mMappedIndexData);
mMappedIndexData = NULL;
mEmpty = TRUE;
sAllocatedBytes -= getIndicesSize();
}
mGLIndices = 0;
//unbind();
}
void LLVertexBuffer::updateNumVerts(S32 nverts)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS);
if (nverts >= 65535)
{
llwarns << "Vertex buffer overflow!" << llendl;
nverts = 65535;
}
mRequestedNumVerts = nverts;
if (!mDynamicSize)
{
mNumVerts = nverts;
}
else if (mUsage == GL_STATIC_DRAW_ARB ||
nverts > mNumVerts ||
nverts < mNumVerts/2)
{
if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535)
{
nverts += nverts/4;
}
mNumVerts = nverts;
}
#if LL_ALIGNED_VB
mStride = calcStride(mTypeMask, mOffsets, mNumVerts);
#endif
}
void LLVertexBuffer::updateNumIndices(S32 nindices)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES);
mRequestedNumIndices = nindices;
if (!mDynamicSize)
{
mNumIndices = nindices;
}
else if (mUsage == GL_STATIC_DRAW_ARB ||
nindices > mNumIndices ||
nindices < mNumIndices/2)
{
if (mUsage != GL_STATIC_DRAW_ARB)
{
nindices += nindices/4;
}
mNumIndices = nindices;
}
}
void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
if (nverts < 0 || nindices < 0 ||
nverts > 65536)
{
llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl;
}
updateNumVerts(nverts);
updateNumIndices(nindices);
if (mMappedData)
{
llerrs << "LLVertexBuffer::allocateBuffer() called redundantly." << llendl;
}
if (create && (nverts || nindices))
{
createGLBuffer();
createGLIndices();
}
sAllocatedBytes += getSize() + getIndicesSize();
}
void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
mRequestedNumVerts = newnverts;
mRequestedNumIndices = newnindices;
LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
mDynamicSize = TRUE;
if (mUsage == GL_STATIC_DRAW_ARB)
{ //always delete/allocate static buffers on resize
destroyGLBuffer();
destroyGLIndices();
allocateBuffer(newnverts, newnindices, TRUE);
mFinal = FALSE;
}
else if (newnverts > mNumVerts || newnindices > mNumIndices ||
newnverts < mNumVerts/2 || newnindices < mNumIndices/2)
{
sAllocatedBytes -= getSize() + getIndicesSize();
updateNumVerts(newnverts);
updateNumIndices(newnindices);
S32 newsize = getSize();
S32 new_index_size = getIndicesSize();
sAllocatedBytes += newsize + new_index_size;
if (newsize)
{
if (!mGLBuffer)
{ //no buffer exists, create a new one
createGLBuffer();
}
else
{
if (!useVBOs())
{
ll_aligned_free_16(mMappedData);
mMappedData = (U8*) ll_aligned_malloc_16(newsize);
}
mResized = TRUE;
}
}
else if (mGLBuffer)
{
destroyGLBuffer();
}
if (new_index_size)
{
if (!mGLIndices)
{
createGLIndices();
}
else
{
if (!useVBOs())
{
ll_aligned_free_16(mMappedIndexData);
mMappedIndexData = (U8*) ll_aligned_malloc_16(new_index_size);
}
mResized = TRUE;
}
}
else if (mGLIndices)
{
destroyGLIndices();
}
}
if (mResized && useVBOs())
{
setBuffer(0);
}
}
BOOL LLVertexBuffer::useVBOs() const
{
//it's generally ineffective to use VBO for things that are streaming on apple
#if LL_DARWIN
if (!mUsage || mUsage == GL_STREAM_DRAW_ARB)
{
return FALSE;
}
#else
if (!mUsage)
{
return FALSE;
}
#endif
}
//----------------------------------------------------------------------------
// Map for data access
U8* LLVertexBuffer::mapBuffer(S32 access)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
if (mFinal)
{
llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl;
}
if (!useVBOs() && !mMappedData && !mMappedIndexData)
{
llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl;
}
if (!mLocked && useVBOs())
{
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
setBuffer(0);
mLocked = TRUE;
stop_glerror();
U8* src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
mAlignedOffset = mMappedData - src;
stop_glerror();
}
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
U8* src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
mMappedIndexData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
mAlignedIndexOffset = mMappedIndexData - src;
stop_glerror();
}
//--------------------
//print out more debug info before crash
llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ;
GLint size ;
glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ;
llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ;
//--------------------
GLint buff;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
{
llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
}
llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
}
if (!mMappedIndexData)
{
GLint buff;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
{
llerrs << "Invalid GL index buffer bound: " << buff << llendl;
}
llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
}
sMappedCount++;
}
return mMappedData;
}
void LLVertexBuffer::unmapBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
if (mMappedData || mMappedIndexData)
{
if (useVBOs() && mLocked)
{
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);