From cf73a329b379945f9538c711469d397e775b1e9a Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 15 Dec 2008 16:42:22 +0000 Subject: [PATCH] From Peter Hrenka, "I implemented a free list reallocation scheme in VertexBufferObject::compileBuffer(). The offsets of newly added Arrays were not properly calculated. This submission tries to find a matching empty slot when the total size of the VBO has not changed (e.g. when an array is replaced by another array of the same size). This fixes the overwriting issue that I showed in my posting "Bug in VertexBufferObject::compileBuffer" on OSG-Users. " --- src/osg/BufferObject.cpp | 77 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/src/osg/BufferObject.cpp b/src/osg/BufferObject.cpp index d7100e1a7..79ff2258e 100644 --- a/src/osg/BufferObject.cpp +++ b/src/osg/BufferObject.cpp @@ -400,6 +400,48 @@ void VertexBufferObject::compileBuffer(State& state) const } } + typedef std::map > SizePosMap_t; + SizePosMap_t freeList; + if (copyAll == false) + { + unsigned int numNewArrays = 0; + std::map usedList; + for(BufferEntryArrayPairs::const_iterator itr = _bufferEntryArrayPairs.begin(); + itr != _bufferEntryArrayPairs.end(); + ++itr) + { + const BufferEntryArrayPair& bep = *itr; + if (bep.second==NULL) continue; + if (bep.first.dataSize == 0) continue; + usedList[bep.first.offset] = bep.first.dataSize; + } + unsigned int numFreeBlocks = 0; + unsigned int pos=0; + + for (std::map::const_iterator it=usedList.begin(); it!=usedList.end(); ++it) + { + unsigned int start = it->first; + unsigned int length = it->second; + if (pos < start) + { + freeList[start-pos].push_back(pos); + ++numFreeBlocks; + } + pos = start+length; + } + if (pos < totalSizeRequired) + { + freeList[totalSizeRequired-pos].push_back(pos); + ++numFreeBlocks; + } + if (numNewArrays < numFreeBlocks) + { + copyAll = true; // too fragmented, fallback to copyAll + freeList.clear(); + } + } + + // osg::Timer_t start_tick = osg::Timer::instance()->tick(); @@ -418,19 +460,42 @@ void VertexBufferObject::compileBuffer(State& state) const const Array* de = bep.second; if (de) { + const unsigned int arraySize = de->getTotalDataSize(); if (copyAll || bep.first.modifiedCount[contextID] != bep.second->getModifiedCount() || - bep.first.dataSize != bep.second->getTotalDataSize()) + bep.first.dataSize != arraySize) { // copy data across - bep.first.dataSize = bep.second->getTotalDataSize(); - bep.first.modifiedCount[contextID] = de->getModifiedCount(); + unsigned int newOffset = bep.first.offset; if (copyAll) { - bep.first.offset = offset; - de->setVertexBufferObjectOffset((GLvoid*)offset); - offset += bep.first.dataSize; + newOffset = offset; + offset += arraySize; } + else if (bep.first.dataSize == 0) + { + SizePosMap_t::iterator findIt = freeList.lower_bound(arraySize); + if (findIt==freeList.end()) + { + osg::notify(osg::FATAL)<<"No suitable Memory in VBO found!"<second.back(); + newOffset = oldOffset; + if (findIt->first > arraySize) // using larger block + { + freeList[findIt->first-arraySize].push_back(oldOffset+arraySize); + } + findIt->second.pop_back(); + if (findIt->second.empty()) + { + freeList.erase(findIt); + } + } + bep.first.dataSize = arraySize; + bep.first.modifiedCount[contextID] = de->getModifiedCount(); + bep.first.offset = newOffset; + de->setVertexBufferObjectOffset((GLvoid*)newOffset); // osg::notify(osg::NOTICE)<<" copying vertex buffer data "<