1
0
forked from mirrors/0ad

Use pool allocator to avoid apparently expensive dynamic allocations when rendering terrain.

Add function to get pool usage, for debugging.

This was SVN commit r9132.
This commit is contained in:
Ykkrosh
2011-03-30 21:42:35 +00:00
parent 98fa860199
commit 1014da1f88
4 changed files with 106 additions and 21 deletions
+5
View File
@@ -119,3 +119,8 @@ void pool_free_all(Pool* p)
da_set_size(&p->da, 0);
}
size_t pool_committed(Pool* p)
{
return p->da.cur_size;
}
+16
View File
@@ -133,6 +133,17 @@ LIB_API void pool_free(Pool* p, void* el);
**/
LIB_API void pool_free_all(Pool* p);
/**
* Return the number of bytes committed in the pool's backing array.
*
* This is roughly the number of bytes allocated in this pool plus the
* unused freelist entries.
*
* @param p Pool*
* @return number of bytes
**/
LIB_API size_t pool_committed(Pool* p);
/**
* C++ wrapper on top of pool_alloc for fixed-size allocations (determined by sizeof(T))
@@ -204,6 +215,11 @@ public:
return t;
}
size_t GetCommittedSize()
{
return pool_committed(&m_pool);
}
private:
Pool m_pool;
};
+83 -21
View File
@@ -20,12 +20,11 @@
#include <set>
#include <algorithm>
#include <boost/tuple/tuple.hpp>
#include "graphics/GameView.h"
#include "graphics/LightEnv.h"
#include "graphics/Patch.h"
#include "graphics/Terrain.h"
#include "lib/allocators/pool.h"
#include "lib/res/graphics/unifont.h"
#include "maths/MathUtil.h"
#include "ps/CLogger.h"
@@ -663,21 +662,53 @@ void CPatchRData::Update()
// Types used for glMultiDrawElements batching:
// To minimise the cost of memory allocations, everything used for computing
// batches uses a pool allocator. (All allocations are short-lived so we can
// just throw away the whole pool at the end of each frame.)
// std::map types with appropriate pool allocators and default comparison operator
#define POOLED_BATCH_MAP(Key, Value) \
std::map<Key, Value, std::less<Key>, pool_allocator<std::pair<Key const, Value> > >
// Equivalent to "m[k]", when it returns a pool-allocated std::map (since we can't
// use the default constructor in that case)
template<typename M>
typename M::mapped_type& PooledMapGet(M& m, const typename M::key_type& k, RawPoolAllocator& pool)
{
return m.insert(std::make_pair(k,
typename M::mapped_type(typename M::mapped_type::key_compare(), typename M::mapped_type::allocator_type(pool))
)).first->second;
}
// Equivalent to "m[k]", when it returns a std::pair of pool-allocated std::vectors
template<typename M>
typename M::mapped_type& PooledPairGet(M& m, const typename M::key_type& k, RawPoolAllocator& pool)
{
return m.insert(std::make_pair(k, std::make_pair(
typename M::mapped_type::first_type(typename M::mapped_type::first_type::allocator_type(pool)),
typename M::mapped_type::second_type(typename M::mapped_type::second_type::allocator_type(pool))
))).first->second;
}
static const size_t POOL_SIZE = 4*MiB; // this should be enough for fairly huge maps
// Each multidraw batch has a list of index counts, and a list of pointers-to-first-indexes
typedef std::pair<std::vector<GLint>, std::vector<void*> > BatchElements;
typedef std::pair<std::vector<GLint, pool_allocator<GLint> >, std::vector<void*, pool_allocator<void*> > > BatchElements;
// Group batches by index buffer
typedef std::map<CVertexBuffer*, BatchElements> IndexBufferBatches;
typedef POOLED_BATCH_MAP(CVertexBuffer*, BatchElements) IndexBufferBatches;
// Group batches by vertex buffer
typedef std::map<CVertexBuffer*, IndexBufferBatches> VertexBufferBatches;
typedef POOLED_BATCH_MAP(CVertexBuffer*, IndexBufferBatches) VertexBufferBatches;
// Group batches by texture
typedef std::map<CTerrainTextureEntry*, VertexBufferBatches> TextureBatches;
typedef POOLED_BATCH_MAP(CTerrainTextureEntry*, VertexBufferBatches) TextureBatches;
void CPatchRData::RenderBases(const std::vector<CPatchRData*>& patches)
{
TextureBatches batches;
RawPoolAllocator pool(POOL_SIZE);
TextureBatches batches (TextureBatches::key_compare(), (TextureBatches::allocator_type(pool)));
PROFILE_START("compute batches");
@@ -689,7 +720,13 @@ void CPatchRData::RenderBases(const std::vector<CPatchRData*>& patches)
{
SSplat& splat = patch->m_Splats[j];
BatchElements& batch = batches[splat.m_Texture][patch->m_VBBase->m_Owner][patch->m_VBBaseIndices->m_Owner];
BatchElements& batch = PooledPairGet(
PooledMapGet(
PooledMapGet(batches, splat.m_Texture, pool),
patch->m_VBBase->m_Owner, pool
),
patch->m_VBBaseIndices->m_Owner, pool
);
batch.first.push_back(splat.m_IndexCount);
@@ -745,13 +782,38 @@ void CPatchRData::RenderBases(const std::vector<CPatchRData*>& patches)
*/
struct SBlendBatch
{
SBlendBatch(RawPoolAllocator& pool) :
m_Batches(VertexBufferBatches::key_compare(), VertexBufferBatches::allocator_type(pool))
{
}
CTerrainTextureEntry* m_Texture;
VertexBufferBatches m_Batches;
};
/**
* Helper structure for RenderBlends.
*/
struct SBlendStackItem
{
SBlendStackItem(CVertexBuffer::VBChunk* v, CVertexBuffer::VBChunk* i,
const std::vector<CPatchRData::SSplat>& s, RawPoolAllocator& pool) :
vertices(v), indices(i), splats(s.begin(), s.end(), SplatStack::allocator_type(pool))
{
}
typedef std::vector<CPatchRData::SSplat, pool_allocator<CPatchRData::SSplat*> > SplatStack;
CVertexBuffer::VBChunk* vertices;
CVertexBuffer::VBChunk* indices;
SplatStack splats;
};
void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches)
{
std::vector<SBlendBatch> batches;
RawPoolAllocator pool(POOL_SIZE);
typedef std::vector<SBlendBatch, pool_allocator<SBlendBatch*> > BatchesStack;
BatchesStack batches((BatchesStack::allocator_type(pool)));
PROFILE_START("compute batches");
@@ -759,8 +821,8 @@ void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches)
// to avoid heavy reallocations
batches.reserve(256);
// Each patch has a vertex buffer, index buffer, and stack of splats
std::vector<boost::tuple<CVertexBuffer::VBChunk*, CVertexBuffer::VBChunk*, std::vector<SSplat> > > blendStacks;
typedef std::vector<SBlendStackItem, pool_allocator<SBlendStackItem*> > BlendStacks;
BlendStacks blendStacks((BlendStacks::allocator_type(pool)));
blendStacks.reserve(patches.size());
// Extract all the blend splats from each patch
@@ -769,9 +831,10 @@ void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches)
CPatchRData* patch = patches[i];
if (!patch->m_BlendSplats.empty())
{
blendStacks.push_back(boost::make_tuple(patch->m_VBBlends, patch->m_VBBlendIndices, patch->m_BlendSplats));
blendStacks.push_back(SBlendStackItem(patch->m_VBBlends, patch->m_VBBlendIndices, patch->m_BlendSplats, pool));
// Reverse the splats so the first to be rendered is at the back of the list
std::reverse(blendStacks.back().get<2>().begin(), blendStacks.back().get<2>().end());
std::reverse(blendStacks.back().splats.begin(), blendStacks.back().splats.end());
}
}
@@ -788,14 +851,13 @@ void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches)
for (size_t k = 0; k < blendStacks.size(); ++k)
{
std::vector<SSplat>& splats = blendStacks[k].get<2>();
SBlendStackItem::SplatStack& splats = blendStacks[k].splats;
if (!splats.empty() && splats.back().m_Texture == tex)
{
CVertexBuffer::VBChunk* vertices = blendStacks[k].get<0>();
CVertexBuffer::VBChunk* indices = blendStacks[k].get<1>();
BatchElements& batch = batches.back().m_Batches[vertices->m_Owner][indices->m_Owner];
CVertexBuffer::VBChunk* vertices = blendStacks[k].vertices;
CVertexBuffer::VBChunk* indices = blendStacks[k].indices;
BatchElements& batch = PooledPairGet(PooledMapGet(batches.back().m_Batches, vertices->m_Owner, pool), indices->m_Owner, pool);
batch.first.push_back(splats.back().m_IndexCount);
u8* indexBase = indices->m_Owner->GetBindAddress();
@@ -811,7 +873,7 @@ void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches)
for (size_t k = 0; k < blendStacks.size(); ++k)
{
std::vector<SSplat>& splats = blendStacks[k].get<2>();
SBlendStackItem::SplatStack& splats = blendStacks[k].splats;
if (splats.size() > bestStackSize)
{
bestStackSize = splats.size();
@@ -822,7 +884,7 @@ void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches)
if (bestStackSize == 0)
break;
SBlendBatch layer;
SBlendBatch layer(pool);
layer.m_Texture = bestTex;
batches.push_back(layer);
}
@@ -831,7 +893,7 @@ void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches)
CVertexBuffer* lastVB = NULL;
for (std::vector<SBlendBatch>::iterator itt = batches.begin(); itt != batches.end(); ++itt)
for (BatchesStack::iterator itt = batches.begin(); itt != batches.end(); ++itt)
{
if (itt->m_Texture)
itt->m_Texture->GetTexture()->Bind();
+2
View File
@@ -48,6 +48,8 @@ public:
CPatch* GetPatch() { return m_Patch; }
private:
friend struct SBlendStackItem;
struct SSplat {
SSplat() : m_Texture(0), m_IndexCount(0) {}