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.
"
This commit is contained in:
Robert Osfield 2008-12-15 16:42:22 +00:00
parent ca3fe5d352
commit cf73a329b3

View File

@ -400,6 +400,48 @@ void VertexBufferObject::compileBuffer(State& state) const
}
}
typedef std::map<unsigned int,std::vector<unsigned int> > SizePosMap_t;
SizePosMap_t freeList;
if (copyAll == false)
{
unsigned int numNewArrays = 0;
std::map<unsigned int,unsigned int> 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<unsigned int,unsigned int>::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!"<<std::endl;
continue;
}
const unsigned int oldOffset = findIt->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 "<<bep.first.dataSize<<" bytes"<<std::endl;