diff options
Diffstat (limited to 'indra/llrender/llvertexbuffer.cpp')
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 296 |
1 files changed, 247 insertions, 49 deletions
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 7caf20f40b..2eb7c21f77 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -290,6 +290,62 @@ static GLuint gen_buffer() #define ANALYZE_VBO_POOL 0 +#if LL_DARWIN + +// experimental -- disable VBO pooling on OS X and use glMapBuffer +class LLVBOPool +{ +public: + U64 mAllocated = 0; + + U64 getVramBytesUsed() + { + return mAllocated; + } + + void allocate(GLenum type, U32 size, GLuint& name, U8*& data) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + STOP_GLERROR; + llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER); + llassert(name == 0); // non zero name indicates a gl name that wasn't freed + llassert(data == nullptr); // non null data indicates a buffer that wasn't freed + llassert(size >= 2); // any buffer size smaller than a single index is nonsensical + + mAllocated += size; + + { //allocate a new buffer + LL_PROFILE_GPU_ZONE("vbo alloc"); + // ON OS X, we don't allocate a VBO until the last possible moment + // in unmapBuffer + data = (U8*) ll_aligned_malloc_16(size); + STOP_GLERROR; + } + } + + void free(GLenum type, U32 size, GLuint name, U8* data) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER); + llassert(size >= 2); + + if (data) + { + ll_aligned_free_16(data); + } + + mAllocated -= size; + STOP_GLERROR; + if (name) + { + glDeleteBuffers(1, &name); + } + STOP_GLERROR; + } +}; + +#else + class LLVBOPool { public: @@ -509,9 +565,8 @@ public: mIBOPool.clear(); mVBOPool.clear(); } - - }; +#endif static LLVBOPool* sVBOPool = nullptr; @@ -545,6 +600,7 @@ const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = sizeof(F32), // TYPE_WEIGHT, sizeof(LLVector4), // TYPE_WEIGHT4, sizeof(LLVector4), // TYPE_CLOTHWEIGHT, + sizeof(U64), // TYPE_JOINT, sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes }; @@ -562,6 +618,7 @@ static const std::string vb_type_name[] = "TYPE_WEIGHT", "TYPE_WEIGHT4", "TYPE_CLOTHWEIGHT", + "TYPE_JOINT" "TYPE_TEXTURE_INDEX", "TYPE_MAX", "TYPE_INDEX", @@ -629,6 +686,8 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; llassert(LLGLSLShader::sCurBoundShaderPtr != NULL); + STOP_GLERROR; + gGL.syncMatrices(); U32 mask = LLVertexBuffer::MAP_VERTEX; @@ -643,7 +702,7 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto if (tc != nullptr) { - for (int i = 0; i < num_indices; ++i) + for (U32 i = 0; i < num_indices; ++i) { U16 idx = indicesp[i]; gGL.texCoord2fv(tc[idx].mV); @@ -652,7 +711,7 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto } else { - for (int i = 0; i < num_indices; ++i) + for (U32 i = 0; i < num_indices; ++i) { U16 idx = indicesp[i]; gGL.vertex3fv(pos[idx].getF32ptr()); @@ -669,24 +728,23 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of return true; } - llassert(start < (U32)mNumVerts); - llassert(end < (U32)mNumVerts); + llassert(start < mNumVerts); + llassert(end < mNumVerts); - if (start >= (U32) mNumVerts || - end >= (U32) mNumVerts) + if (start >= mNumVerts || + end >= mNumVerts) { LL_ERRS() << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << LL_ENDL; } - llassert(mNumIndices >= 0); - - if (indices_offset >= (U32) mNumIndices || - indices_offset + count > (U32) mNumIndices) + if (indices_offset >= mNumIndices || + indices_offset + count > mNumIndices) { LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << LL_ENDL; } { +#if 0 // not a reliable test for VBOs that are not backed by a CPU buffer U16* idx = (U16*) mMappedIndexData+indices_offset; for (U32 i = 0; i < count; ++i) { @@ -718,12 +776,13 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of for (U32 i = start; i < end; i++) { U32 idx = (U32) (v[i][3]+0.25f); - if (idx >= shader->mFeatures.mIndexedTextureChannels) + if (idx >= (U32)shader->mFeatures.mIndexedTextureChannels) { LL_ERRS() << "Bad texture index found in vertex data stream." << LL_ENDL; } } } +#endif } return true; @@ -741,10 +800,19 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi llassert(mGLBuffer == sGLRenderBuffer); llassert(mGLIndices == sGLRenderIndices); gGL.syncMatrices(); + STOP_GLERROR; glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType, (GLvoid*) (indices_offset * (size_t) mIndicesStride)); + STOP_GLERROR; } +void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const +{ + glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType, + (GLvoid*)(indices_offset * (size_t)mIndicesStride)); +} + + void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { drawRange(mode, 0, mNumVerts-1, count, indices_offset); @@ -758,7 +826,9 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const llassert(mGLIndices == sGLRenderIndices); gGL.syncMatrices(); + STOP_GLERROR; glDrawArrays(sGLMode[mode], first, count); + STOP_GLERROR; } //static @@ -781,9 +851,10 @@ void LLVertexBuffer::initClass(LLWindow* window) //static void LLVertexBuffer::unbind() { + STOP_GLERROR; glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - + STOP_GLERROR; sGLRenderBuffer = 0; sGLRenderIndices = 0; } @@ -998,12 +1069,6 @@ bool LLVertexBuffer::updateNumVerts(U32 nverts) bool success = true; - if (nverts > 65536) - { - LL_WARNS() << "Vertex buffer overflow!" << LL_ENDL; - nverts = 65536; - } - U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); if (needed_size != mSize) @@ -1036,8 +1101,7 @@ bool LLVertexBuffer::updateNumIndices(U32 nindices) bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices) { - if (nverts < 0 || nindices < 0 || - nverts > 65536) + if (nverts < 0 || nindices < 0) { LL_ERRS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL; } @@ -1080,6 +1144,7 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde count = mNumVerts - index; } +#if !LL_DARWIN U32 start = mOffsets[type] + sTypeSize[type] * index; U32 end = start + sTypeSize[type] * count-1; @@ -1100,7 +1165,7 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde //didn't expand an existing region, make a new one mMappedVertexRegions.push_back({ start, end }); } - +#endif return mMappedData+mOffsets[type]+sTypeSize[type]*index; } @@ -1114,6 +1179,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count) count = mNumIndices-index; } +#if !LL_DARWIN U32 start = sizeof(U16) * index; U32 end = start + sizeof(U16) * count-1; @@ -1134,6 +1200,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count) //didn't expand an existing region, make a new one mMappedIndexRegions.push_back({ start, end }); } +#endif return mMappedIndexData + sizeof(U16)*index; } @@ -1142,9 +1209,19 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count) // target -- "target" parameter for glBufferSubData // start -- first byte to copy // end -- last byte to copy (NOT last byte + 1) -// data -- mMappedData or mMappedIndexData -static void flush_vbo(GLenum target, U32 start, U32 end, void* data) -{ +// data -- data to be flushed +// dst -- mMappedData or mMappedIndexData +void LLVertexBuffer::flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst) +{ +#if LL_DARWIN + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy"); + STOP_GLERROR; + // copy into mapped buffer + memcpy(dst+start, data, end-start+1); +#else + llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices); + + // skip mapped data and stream to GPU via glBufferSubData if (end != 0) { LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData"); @@ -1163,10 +1240,12 @@ static void flush_vbo(GLenum target, U32 start, U32 end, void* data) glBufferSubData(target, i, size, (U8*) data + (i-start)); } } +#endif } void LLVertexBuffer::unmapBuffer() { + STOP_GLERROR; struct SortMappedRegion { bool operator()(const MappedRegion& lhs, const MappedRegion& rhs) @@ -1175,9 +1254,51 @@ void LLVertexBuffer::unmapBuffer() } }; +#if LL_DARWIN + STOP_GLERROR; + if (mMappedData) + { + if (mGLBuffer) + { + glDeleteBuffers(1, &mGLBuffer); + } + mGLBuffer = gen_buffer(); + glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer); + sGLRenderBuffer = mGLBuffer; + glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW); + } + else if (mGLBuffer != sGLRenderBuffer) + { + glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer); + sGLRenderBuffer = mGLBuffer; + } + STOP_GLERROR; + + if (mMappedIndexData) + { + if (mGLIndices) + { + glDeleteBuffers(1, &mGLIndices); + } + + mGLIndices = gen_buffer(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); + sGLRenderIndices = mGLIndices; + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW); + } + else if (mGLIndices != sGLRenderIndices) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); + sGLRenderIndices = mGLIndices; + } + STOP_GLERROR; +#else + if (!mMappedVertexRegions.empty()) { LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex"); + if (sGLRenderBuffer != mGLBuffer) { glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer); @@ -1198,14 +1319,13 @@ void LLVertexBuffer::unmapBuffer() } else { - flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start); + flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData); start = region.mStart; end = region.mEnd; } } - flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start); - + flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData); mMappedVertexRegions.clear(); } @@ -1232,16 +1352,16 @@ void LLVertexBuffer::unmapBuffer() } else { - flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start); + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData); start = region.mStart; end = region.mEnd; } } - flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start); - + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData); mMappedIndexRegions.clear(); } +#endif } //---------------------------------------------------------------------------- @@ -1362,6 +1482,13 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, U32 in // Set for rendering void LLVertexBuffer::setBuffer() { + STOP_GLERROR; +#if LL_DARWIN + if (!mGLBuffer) + { // OS X doesn't allocate a buffer until we call unmapBuffer + return; + } +#endif // no data may be pending llassert(mMappedVertexRegions.empty()); llassert(mMappedIndexRegions.empty()); @@ -1394,12 +1521,15 @@ void LLVertexBuffer::setBuffer() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); sGLRenderIndices = mGLIndices; } + + STOP_GLERROR; } // virtual (default) void LLVertexBuffer::setupVertexBuffer() { + STOP_GLERROR; U8* base = nullptr; U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask; @@ -1471,6 +1601,12 @@ void LLVertexBuffer::setupVertexBuffer() void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]); glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); } + if (data_mask & MAP_JOINT) + { + AttributeType loc = TYPE_JOINT; + void* ptr = (void*)(base + mOffsets[TYPE_JOINT]); + glVertexAttribIPointer(loc, 4, GL_UNSIGNED_SHORT, LLVertexBuffer::sTypeSize[TYPE_JOINT], ptr); + } if (data_mask & MAP_CLOTHWEIGHT) { AttributeType loc = TYPE_CLOTHWEIGHT; @@ -1489,59 +1625,121 @@ void LLVertexBuffer::setupVertexBuffer() void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]); glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); } + STOP_GLERROR; } void LLVertexBuffer::setPositionData(const LLVector4a* data) { - llassert(sGLRenderBuffer == mGLBuffer); - flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data); + flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data, mMappedData); } -void LLVertexBuffer::setTexCoordData(const LLVector2* data) +void LLVertexBuffer::setTexCoord0Data(const LLVector2* data) { - llassert(sGLRenderBuffer == mGLBuffer); - flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data); + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setTexCoord1Data(const LLVector2* data) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD1], mOffsets[TYPE_TEXCOORD1] + sTypeSize[TYPE_TEXCOORD1] * getNumVerts() - 1, (U8*)data, mMappedData); } void LLVertexBuffer::setColorData(const LLColor4U* data) { - llassert(sGLRenderBuffer == mGLBuffer); - flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data); + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data, mMappedData); } void LLVertexBuffer::setNormalData(const LLVector4a* data) { - llassert(sGLRenderBuffer == mGLBuffer); - flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + sTypeSize[TYPE_NORMAL] * getNumVerts() - 1, (U8*) data); + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + sTypeSize[TYPE_NORMAL] * getNumVerts() - 1, (U8*) data, mMappedData); } void LLVertexBuffer::setTangentData(const LLVector4a* data) { - llassert(sGLRenderBuffer == mGLBuffer); - flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + sTypeSize[TYPE_TANGENT] * getNumVerts() - 1, (U8*) data); + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + sTypeSize[TYPE_TANGENT] * getNumVerts() - 1, (U8*) data, mMappedData); } void LLVertexBuffer::setWeight4Data(const LLVector4a* data) { - llassert(sGLRenderBuffer == mGLBuffer); - flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + sTypeSize[TYPE_WEIGHT4] * getNumVerts() - 1, (U8*) data); + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + sTypeSize[TYPE_WEIGHT4] * getNumVerts() - 1, (U8*) data, mMappedData); +} + +void LLVertexBuffer::setJointData(const U64* data) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_JOINT], mOffsets[TYPE_JOINT] + sTypeSize[TYPE_JOINT] * getNumVerts() - 1, (U8*) data, mMappedData); } void LLVertexBuffer::setIndexData(const U16* data) { - llassert(sGLRenderIndices == mGLIndices); - flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * getNumIndices() - 1, (U8*) data); + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * getNumIndices() - 1, (U8*) data, mMappedIndexData); } void LLVertexBuffer::setIndexData(const U32* data) { - llassert(sGLRenderIndices == mGLIndices); if (mIndicesType != GL_UNSIGNED_INT) { // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices mIndicesType = GL_UNSIGNED_INT; mIndicesStride = 4; mNumIndices /= 2; } - flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * getNumIndices() - 1, (U8*)data); + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * getNumIndices() - 1, (U8*)data, mMappedIndexData); +} + +void LLVertexBuffer::setPositionData(const LLVector4a* data, U32 offset, U32 count) +{ + flush_vbo(GL_ARRAY_BUFFER, offset * sizeof(LLVector4a), (offset + count) * sizeof(LLVector4a) - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setNormalData(const LLVector4a* data, U32 offset, U32 count) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL] + offset * sTypeSize[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + (offset + count) * sTypeSize[TYPE_NORMAL] - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setTexCoord0Data(const LLVector2* data, U32 offset, U32 count) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0] + offset * sTypeSize[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + (offset + count) * sTypeSize[TYPE_TEXCOORD0] - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setTexCoord1Data(const LLVector2* data, U32 offset, U32 count) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD1] + offset * sTypeSize[TYPE_TEXCOORD1], mOffsets[TYPE_TEXCOORD1] + (offset + count) * sTypeSize[TYPE_TEXCOORD1] - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setColorData(const LLColor4U* data, U32 offset, U32 count) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR] + offset * sTypeSize[TYPE_COLOR], mOffsets[TYPE_COLOR] + (offset + count) * sTypeSize[TYPE_COLOR] - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setTangentData(const LLVector4a* data, U32 offset, U32 count) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT] + offset * sTypeSize[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + (offset + count) * sTypeSize[TYPE_TANGENT] - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setWeight4Data(const LLVector4a* data, U32 offset, U32 count) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4] + offset * sTypeSize[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + (offset + count) * sTypeSize[TYPE_WEIGHT4] - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setJointData(const U64* data, U32 offset, U32 count) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_JOINT] + offset * sTypeSize[TYPE_JOINT], mOffsets[TYPE_JOINT] + (offset + count) * sTypeSize[TYPE_JOINT] - 1, (U8*)data, mMappedData); +} + +void LLVertexBuffer::setIndexData(const U16* data, U32 offset, U32 count) +{ + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U16), (offset + count) * sizeof(U16) - 1, (U8*)data, mMappedIndexData); +} + +void LLVertexBuffer::setIndexData(const U32* data, U32 offset, U32 count) +{ + if (mIndicesType != GL_UNSIGNED_INT) + { // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices + mIndicesType = GL_UNSIGNED_INT; + mIndicesStride = 4; + mNumIndices /= 2; + } + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U32), (offset + count) * sizeof(U32) - 1, (U8*)data, mMappedIndexData); } + + + |