diff options
author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-10-17 16:56:21 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-17 16:56:21 +0300 |
commit | 0ef7a9b39cf72da1211039ab22bdf8f9f6a2c984 (patch) | |
tree | 6f51ef179497265b5bff2a355471ae5dc9643ad2 /indra/llrender/llvertexbuffer.cpp | |
parent | 9e24b300d02e5627ea0d304d412cb683ec2de3a4 (diff) | |
parent | d3d349ae0f17a72481f30b9354b9367b1cd3b639 (diff) |
Merge pull request #2856 from secondlife/marchcat/c-develop
Develop → Maint C sync
Diffstat (limited to 'indra/llrender/llvertexbuffer.cpp')
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 646 |
1 files changed, 508 insertions, 138 deletions
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 7caf20f40b..12ae36f4bb 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -36,6 +36,7 @@ #include "llshadermgr.h" #include "llglslshader.h" #include "llmemory.h" +#include <glm/gtc/type_ptr.hpp> //Next Highest Power Of Two //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 @@ -288,13 +289,103 @@ static GLuint gen_buffer() return ret; } +static void delete_buffers(S32 count, GLuint* buffers) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + // wait a few frames before actually deleting the buffers to avoid + // synchronization issues with the GPU + static std::vector<GLuint> sFreeList[4]; + + if (gGLManager.mInited) + { + U32 idx = LLImageGL::sFrameCount % 4; + + for (S32 i = 0; i < count; ++i) + { + sFreeList[idx].push_back(buffers[i]); + } + + idx = (LLImageGL::sFrameCount + 3) % 4; + + if (!sFreeList[idx].empty()) + { + glDeleteBuffers((GLsizei)sFreeList[idx].size(), sFreeList[idx].data()); + sFreeList[idx].resize(0); + } + } +} + + #define ANALYZE_VBO_POOL 0 +// VBO Pool interface class LLVBOPool { + public: + virtual ~LLVBOPool() = default; + virtual void allocate(GLenum type, U32 size, GLuint& name, U8*& data) = 0; + virtual void free(GLenum type, U32 size, GLuint name, U8* data) = 0; + virtual U64 getVramBytesUsed() = 0; +}; + +// VBO Pool for Apple GPUs (as in M1/M2 etc, not Intel macs) +// Effectively disables VBO pooling +class LLAppleVBOPool final: public LLVBOPool +{ public: - typedef std::chrono::steady_clock::time_point Time; + U64 mAllocated = 0; + + U64 getVramBytesUsed() override + { + return mAllocated; + } + + void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override + { + 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) override + { + 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) + { + delete_buffers(1, &name); + } + STOP_GLERROR; + } +}; + +// VBO Pool for GPUs that benefit from VBO pooling +class LLDefaultVBOPool final : public LLVBOPool +{ +public: + typedef std::chrono::steady_clock::time_point Time; struct Entry { U8* mData; @@ -302,7 +393,7 @@ public: Time mAge; }; - ~LLVBOPool() + ~LLDefaultVBOPool() override { clear(); } @@ -320,7 +411,7 @@ public: U32 mMisses = 0; U32 mHits = 0; - U64 getVramBytesUsed() + U64 getVramBytesUsed() override { return mAllocated + mReserved; } @@ -336,7 +427,7 @@ public: size += block_size - (size % block_size); } - void allocate(GLenum type, U32 size, GLuint& name, U8*& data) + void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER); @@ -392,7 +483,7 @@ public: clean(); } - void free(GLenum type, U32 size, GLuint name, U8* data) + void free(GLenum type, U32 size, GLuint name, U8* data) override { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER); @@ -455,7 +546,7 @@ public: LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vbo cache timeout"); auto& entry = entries.back(); ll_aligned_free_16(entry.mData); - glDeleteBuffers(1, &entry.mGLName); + delete_buffers(1, &entry.mGLName); llassert(mReserved >= iter->first); mReserved -= iter->first; entries.pop_back(); @@ -491,7 +582,7 @@ public: for (auto& entry : entries.second) { ll_aligned_free_16(entry.mData); - glDeleteBuffers(1, &entry.mGLName); + delete_buffers(1, &entry.mGLName); } } @@ -500,7 +591,7 @@ public: for (auto& entry : entries.second) { ll_aligned_free_16(entry.mData); - glDeleteBuffers(1, &entry.mGLName); + delete_buffers(1, &entry.mGLName); } } @@ -509,12 +600,72 @@ public: mIBOPool.clear(); mVBOPool.clear(); } - - }; static LLVBOPool* sVBOPool = nullptr; +void LLVertexBufferData::drawWithMatrix() +{ + if (!mVB) + { + llassert(false); + // Not supposed to happen, check buffer generation + return; + } + + if (mTexName) + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName); + } + else + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadMatrix(glm::value_ptr(mModelView)); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadMatrix(glm::value_ptr(mProjection)); + gGL.matrixMode(LLRender::MM_TEXTURE0); + gGL.pushMatrix(); + gGL.loadMatrix(glm::value_ptr(mTexture0)); + + mVB->setBuffer(); + mVB->drawArrays(mMode, 0, mCount); + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); +} + +void LLVertexBufferData::draw() +{ + if (!mVB) + { + llassert(false); + // Not supposed to happen, check buffer generation + return; + } + + if (mTexName) + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName); + } + else + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + + mVB->setBuffer(); + mVB->drawArrays(mMode, 0, mCount); +} + +//============================================================================ + //static U64 LLVertexBuffer::getBytesAllocated() { @@ -545,6 +696,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 +714,7 @@ static const std::string vb_type_name[] = "TYPE_WEIGHT", "TYPE_WEIGHT4", "TYPE_CLOTHWEIGHT", + "TYPE_JOINT" "TYPE_TEXTURE_INDEX", "TYPE_MAX", "TYPE_INDEX", @@ -575,7 +728,6 @@ const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = GL_POINTS, GL_LINES, GL_LINE_STRIP, - GL_QUADS, GL_LINE_LOOP, }; @@ -629,6 +781,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 +797,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 +806,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 +823,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 +871,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; @@ -735,16 +889,37 @@ void LLVertexBuffer::setLabel(const char* label) { } #endif +void LLVertexBuffer::clone(LLVertexBuffer& target) const +{ + target.mTypeMask = mTypeMask; + target.mIndicesType = mIndicesType; + target.mIndicesStride = mIndicesStride; + if (target.getNumVerts() != getNumVerts() || + target.getNumIndices() != getNumIndices()) + { + target.allocateBuffer(getNumVerts(), getNumIndices()); + } +} + void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const { llassert(validateRange(start, end, count, indices_offset)); 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,14 +933,25 @@ 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 void LLVertexBuffer::initClass(LLWindow* window) { llassert(sVBOPool == nullptr); - sVBOPool = new LLVBOPool(); + if (gGLManager.mIsApple) + { + LL_INFOS() << "VBO Pooling Disabled" << LL_ENDL; + sVBOPool = new LLAppleVBOPool(); + } + else + { + LL_INFOS() << "VBO Pooling Enabled" << LL_ENDL; + sVBOPool = new LLDefaultVBOPool(); + } #if ENABLE_GL_WORK_QUEUE sQueue = new GLWorkQueue(); @@ -781,9 +967,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; } @@ -823,6 +1010,24 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask) } } +// list of mapped buffers +// NOTE: must not be LLPointer<LLVertexBuffer> to avoid breaking non-ref-counted LLVertexBuffer instances +static std::vector<LLVertexBuffer*> sMappedBuffers; + +//static +void LLVertexBuffer::flushBuffers() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + // must only be called from main thread + for (auto& buffer : sMappedBuffers) + { + buffer->_unmapBuffer(); + buffer->mMapped = false; + } + + sMappedBuffers.resize(0); +} + //static U32 LLVertexBuffer::calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices) { @@ -866,6 +1071,12 @@ U32 LLVertexBuffer::calcVertexSize(const U32& typemask) //virtual LLVertexBuffer::~LLVertexBuffer() { + if (mMapped) + { // is on the mapped buffer list but doesn't need to be flushed + mMapped = false; + unmapBuffer(); + } + destroyGLBuffer(); destroyGLIndices(); @@ -998,12 +1209,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 +1241,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; } @@ -1074,33 +1278,36 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start, U32 end) U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 index, S32 count) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + _mapBuffer(); if (count == -1) { count = mNumVerts - index; } - U32 start = mOffsets[type] + sTypeSize[type] * index; - U32 end = start + sTypeSize[type] * count-1; - - bool flagged = false; - // flag region as mapped - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) + if (!gGLManager.mIsApple) { - MappedRegion& region = mMappedVertexRegions[i]; - if (expand_region(region, start, end)) + U32 start = mOffsets[type] + sTypeSize[type] * index; + U32 end = start + sTypeSize[type] * count-1; + + bool flagged = false; + // flag region as mapped + for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) { - flagged = true; - break; + MappedRegion& region = mMappedVertexRegions[i]; + if (expand_region(region, start, end)) + { + flagged = true; + break; + } } - } - if (!flagged) - { - //didn't expand an existing region, make a new one - mMappedVertexRegions.push_back({ start, end }); + if (!flagged) + { + //didn't expand an existing region, make a new one + mMappedVertexRegions.push_back({ start, end }); + } } - return mMappedData+mOffsets[type]+sTypeSize[type]*index; } @@ -1108,31 +1315,35 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + _mapBuffer(); if (count == -1) { count = mNumIndices-index; } - U32 start = sizeof(U16) * index; - U32 end = start + sizeof(U16) * count-1; - - bool flagged = false; - // flag region as mapped - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) + if (!gGLManager.mIsApple) { - MappedRegion& region = mMappedIndexRegions[i]; - if (expand_region(region, start, end)) + U32 start = sizeof(U16) * index; + U32 end = start + sizeof(U16) * count-1; + + bool flagged = false; + // flag region as mapped + for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) { - flagged = true; - break; + MappedRegion& region = mMappedIndexRegions[i]; + if (expand_region(region, start, end)) + { + flagged = true; + break; + } } - } - if (!flagged) - { - //didn't expand an existing region, make a new one - mMappedIndexRegions.push_back({ start, end }); + if (!flagged) + { + //didn't expand an existing region, make a new one + mMappedIndexRegions.push_back({ start, end }); + } } return mMappedIndexData + sizeof(U16)*index; @@ -1142,31 +1353,68 @@ 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 (end != 0) + if (gGLManager.mIsApple) { - LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData"); - LL_PROFILE_ZONE_NUM(start); - LL_PROFILE_ZONE_NUM(end); - LL_PROFILE_ZONE_NUM(end-start); - - constexpr U32 block_size = 8192; + // on OS X, flush_vbo doesn't actually write to the GL buffer, so be sure to call + // _mapBuffer to tag the buffer for flushing to GL + _mapBuffer(); + 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); - for (U32 i = start; i <= end; i += block_size) + // skip mapped data and stream to GPU via glBufferSubData + if (end != 0) { - LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block"); - //LL_PROFILE_GPU_ZONE("glBufferSubData"); - U32 tend = llmin(i + block_size, end); - U32 size = tend - i + 1; - glBufferSubData(target, i, size, (U8*) data + (i-start)); + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData"); + LL_PROFILE_ZONE_NUM(start); + LL_PROFILE_ZONE_NUM(end); + LL_PROFILE_ZONE_NUM(end-start); + + constexpr U32 block_size = 65536; + + for (U32 i = start; i <= end; i += block_size) + { + //LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block"); + //LL_PROFILE_GPU_ZONE("glBufferSubData"); + U32 tend = llmin(i + block_size, end); + U32 size = tend - i + 1; + glBufferSubData(target, i, size, (U8*) data + (i-start)); + } } } } void LLVertexBuffer::unmapBuffer() { + flushBuffers(); +} + +void LLVertexBuffer::_mapBuffer() +{ + if (!mMapped) + { + mMapped = true; + sMappedBuffers.push_back(this); + } +} + +void LLVertexBuffer::_unmapBuffer() +{ + STOP_GLERROR; + if (!mMapped) + { + return; + } + struct SortMappedRegion { bool operator()(const MappedRegion& lhs, const MappedRegion& rhs) @@ -1175,72 +1423,115 @@ void LLVertexBuffer::unmapBuffer() } }; - if (!mMappedVertexRegions.empty()) + if (gGLManager.mIsApple) { - LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex"); - if (sGLRenderBuffer != mGLBuffer) + STOP_GLERROR; + if (mMappedData) { + if (mGLBuffer) + { + delete_buffers(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; - U32 start = 0; - U32 end = 0; - - std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion()); - - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) + if (mMappedIndexData) { - const MappedRegion& region = mMappedVertexRegions[i]; - if (region.mStart == end + 1) - { - end = region.mEnd; - } - else + if (mGLIndices) { - flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start); - start = region.mStart; - end = region.mEnd; + delete_buffers(1, &mGLIndices); } - } - - flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start); - - mMappedVertexRegions.clear(); - } - if (!mMappedIndexRegions.empty()) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index"); + mGLIndices = gen_buffer(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); + sGLRenderIndices = mGLIndices; - if (mGLIndices != sGLRenderIndices) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW); + } + else if (mGLIndices != sGLRenderIndices) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); sGLRenderIndices = mGLIndices; } - U32 start = 0; - U32 end = 0; - - std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion()); - - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) + STOP_GLERROR; + } + else + { + if (!mMappedVertexRegions.empty()) { - const MappedRegion& region = mMappedIndexRegions[i]; - if (region.mStart == end + 1) + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex"); + + if (sGLRenderBuffer != mGLBuffer) { - end = region.mEnd; + glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer); + sGLRenderBuffer = mGLBuffer; } - else + + U32 start = 0; + U32 end = 0; + + std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion()); + + for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) { - flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start); - start = region.mStart; - end = region.mEnd; + const MappedRegion& region = mMappedVertexRegions[i]; + if (region.mStart == end + 1) + { + end = region.mEnd; + } + else + { + 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, mMappedData); + mMappedVertexRegions.clear(); } - flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start); + if (!mMappedIndexRegions.empty()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index"); + + if (mGLIndices != sGLRenderIndices) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); + sGLRenderIndices = mGLIndices; + } + U32 start = 0; + U32 end = 0; + + std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion()); + + for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) + { + const MappedRegion& region = mMappedIndexRegions[i]; + if (region.mStart == end + 1) + { + end = region.mEnd; + } + else + { + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData); + start = region.mStart; + end = region.mEnd; + } + } - mMappedIndexRegions.clear(); + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData); + mMappedIndexRegions.clear(); + } } } @@ -1362,6 +1653,14 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, U32 in // Set for rendering void LLVertexBuffer::setBuffer() { + STOP_GLERROR; + + if (mMapped) + { + LL_WARNS_ONCE() << "Missing call to unmapBuffer or flushBuffers" << LL_ENDL; + _unmapBuffer(); + } + // no data may be pending llassert(mMappedVertexRegions.empty()); llassert(mMappedIndexRegions.empty()); @@ -1394,12 +1693,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 +1773,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 +1797,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::setTexCoord0Data(const LLVector2* data) +{ + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data, mMappedData); } -void LLVertexBuffer::setTexCoordData(const LLVector2* data) +void LLVertexBuffer::setTexCoord1Data(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_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); } + + + |