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 "<