Refactor BufferCache to allow caching buffers of different sizes

0.6.1
scrawl 8 years ago
parent 9a3a64f0c4
commit 274690f790

@ -178,56 +178,56 @@ osg::ref_ptr<IndexArrayType> createIndexBuffer(unsigned int flags, unsigned int
namespace Terrain
{
osg::ref_ptr<osg::Vec2Array> BufferCache::getUVBuffer()
osg::ref_ptr<osg::Vec2Array> BufferCache::getUVBuffer(unsigned int numVerts)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mUvBufferMutex);
if (mUvBufferMap.find(mNumVerts) != mUvBufferMap.end())
if (mUvBufferMap.find(numVerts) != mUvBufferMap.end())
{
return mUvBufferMap[mNumVerts];
return mUvBufferMap[numVerts];
}
int vertexCount = mNumVerts * mNumVerts;
int vertexCount = numVerts * numVerts;
osg::ref_ptr<osg::Vec2Array> uvs (new osg::Vec2Array);
uvs->reserve(vertexCount);
for (unsigned int col = 0; col < mNumVerts; ++col)
for (unsigned int col = 0; col < numVerts; ++col)
{
for (unsigned int row = 0; row < mNumVerts; ++row)
for (unsigned int row = 0; row < numVerts; ++row)
{
uvs->push_back(osg::Vec2f(col / static_cast<float>(mNumVerts-1),
((mNumVerts-1) - row) / static_cast<float>(mNumVerts-1)));
uvs->push_back(osg::Vec2f(col / static_cast<float>(numVerts-1),
((numVerts-1) - row) / static_cast<float>(numVerts-1)));
}
}
// Assign a VBO here to enable state sharing between different Geometries.
uvs->setVertexBufferObject(new osg::VertexBufferObject);
mUvBufferMap[mNumVerts] = uvs;
mUvBufferMap[numVerts] = uvs;
return uvs;
}
osg::ref_ptr<osg::DrawElements> BufferCache::getIndexBuffer(unsigned int flags)
osg::ref_ptr<osg::DrawElements> BufferCache::getIndexBuffer(unsigned int numVerts, unsigned int flags)
{
std::pair<int, int> id = std::make_pair(numVerts, flags);
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mIndexBufferMutex);
unsigned int verts = mNumVerts;
if (mIndexBufferMap.find(flags) != mIndexBufferMap.end())
if (mIndexBufferMap.find(id) != mIndexBufferMap.end())
{
return mIndexBufferMap[flags];
return mIndexBufferMap[id];
}
osg::ref_ptr<osg::DrawElements> buffer;
if (verts*verts <= (0xffffu))
buffer = createIndexBuffer<osg::DrawElementsUShort>(flags, verts);
if (numVerts*numVerts <= (0xffffu))
buffer = createIndexBuffer<osg::DrawElementsUShort>(flags, numVerts);
else
buffer = createIndexBuffer<osg::DrawElementsUInt>(flags, verts);
buffer = createIndexBuffer<osg::DrawElementsUInt>(flags, numVerts);
// Assign a EBO here to enable state sharing between different Geometries.
buffer->setElementBufferObject(new osg::ElementBufferObject);
mIndexBufferMap[flags] = buffer;
mIndexBufferMap[id] = buffer;
return buffer;
}

@ -14,28 +14,24 @@ namespace Terrain
class BufferCache
{
public:
BufferCache(unsigned int numVerts) : mNumVerts(numVerts) {}
/// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each)
/// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices)
/// @note Thread safe.
osg::ref_ptr<osg::DrawElements> getIndexBuffer (unsigned int flags);
osg::ref_ptr<osg::DrawElements> getIndexBuffer (unsigned int numVerts, unsigned int flags);
/// @note Thread safe.
osg::ref_ptr<osg::Vec2Array> getUVBuffer();
osg::ref_ptr<osg::Vec2Array> getUVBuffer(unsigned int numVerts);
// TODO: add releaseGLObjects() for our vertex/element buffer objects
private:
// Index buffers are shared across terrain batches where possible. There is one index buffer for each
// combination of LOD deltas and index buffer LOD we may need.
std::map<int, osg::ref_ptr<osg::DrawElements> > mIndexBufferMap;
std::map<std::pair<int, int>, osg::ref_ptr<osg::DrawElements> > mIndexBufferMap;
OpenThreads::Mutex mIndexBufferMutex;
std::map<int, osg::ref_ptr<osg::Vec2Array> > mUvBufferMap;
OpenThreads::Mutex mUvBufferMutex;
unsigned int mNumVerts;
};
}

@ -51,7 +51,6 @@ namespace Terrain
TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, Shader::ShaderManager* shaderManager, SceneUtil::UnrefQueue* unrefQueue)
: Terrain::World(parent, resourceSystem, ico, storage, nodeMask)
, mNumSplits(4)
, mCache((storage->getCellVertices()-1)/static_cast<float>(mNumSplits) + 1)
, mUnrefQueue(unrefQueue)
, mShaderManager(shaderManager)
{
@ -130,7 +129,9 @@ osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chu
geometry->setUseDisplayList(false);
geometry->setUseVertexBufferObjects(true);
geometry->addPrimitiveSet(mCache.getIndexBuffer(0));
unsigned int numVerts = (mStorage->getCellVertices()-1) * chunkSize + 1;
geometry->addPrimitiveSet(mCache.getIndexBuffer(numVerts, 0));
// we already know the bounding box, so no need to let OSG compute it.
osg::Vec3f min(-0.5f*mStorage->getCellWorldSize()*chunkSize,
@ -184,7 +185,7 @@ osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chu
// use texture coordinates for both texture units, the layer texture and blend texture
for (unsigned int i=0; i<2; ++i)
geometry->setTexCoordArray(i, mCache.getUVBuffer());
geometry->setTexCoordArray(i, mCache.getUVBuffer(numVerts));
float blendmapScale = ESM::Land::LAND_TEXTURE_SIZE*chunkSize;

Loading…
Cancel
Save