Support storing index data in VBOs.
Use index VBOs in model renderers, for performance. Be more explicit about static/dynamic VBOs. Add VBO usage to renderer stats. Clean up some obsolete unused code. This was SVN commit r9052.
This commit is contained in:
parent
b70a0a5b5a
commit
2f28b07356
@ -43,7 +43,7 @@
|
||||
struct FFModelDef : public CModelDefRPrivate
|
||||
{
|
||||
/// Indices are the same for all models, so share them
|
||||
u16* m_Indices;
|
||||
VertexIndexArray m_IndexArray;
|
||||
|
||||
/// Static per-CModelDef vertex array
|
||||
VertexArray m_Array;
|
||||
@ -52,12 +52,11 @@ struct FFModelDef : public CModelDefRPrivate
|
||||
VertexArray::Attribute m_UV;
|
||||
|
||||
FFModelDef(const CModelDefPtr& mdef);
|
||||
~FFModelDef() { delete[] m_Indices; }
|
||||
};
|
||||
|
||||
|
||||
FFModelDef::FFModelDef(const CModelDefPtr& mdef)
|
||||
: m_Array(false)
|
||||
: m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
|
||||
{
|
||||
size_t numVertices = mdef->GetNumVertices();
|
||||
|
||||
@ -75,8 +74,11 @@ FFModelDef::FFModelDef(const CModelDefPtr& mdef)
|
||||
m_Array.Upload();
|
||||
m_Array.FreeBackingStore();
|
||||
|
||||
m_Indices = new u16[mdef->GetNumFaces()*3];
|
||||
ModelRenderer::BuildIndices(mdef, m_Indices);
|
||||
m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
|
||||
m_IndexArray.Layout();
|
||||
ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
|
||||
m_IndexArray.Upload();
|
||||
m_IndexArray.FreeBackingStore();
|
||||
}
|
||||
|
||||
|
||||
@ -89,7 +91,7 @@ struct FFModel
|
||||
VertexArray::Attribute m_Position;
|
||||
VertexArray::Attribute m_Color;
|
||||
|
||||
FFModel() : m_Array(true) { }
|
||||
FFModel() : m_Array(GL_DYNAMIC_DRAW) { }
|
||||
};
|
||||
|
||||
|
||||
@ -267,6 +269,8 @@ void FixedFunctionModelRenderer::RenderModel(int streamflags, CModel* model, voi
|
||||
u8* base = ffmodel->m_Array.Bind();
|
||||
GLsizei stride = (GLsizei)ffmodel->m_Array.GetStride();
|
||||
|
||||
u8* indexBase = m->ffmodeldef->m_IndexArray.Bind();
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, stride, base + ffmodel->m_Position.offset);
|
||||
if (streamflags & STREAM_COLOR)
|
||||
glColorPointer(3, ffmodel->m_Color.type, stride, base + ffmodel->m_Color.offset);
|
||||
@ -284,7 +288,7 @@ void FixedFunctionModelRenderer::RenderModel(int streamflags, CModel* model, voi
|
||||
|
||||
if (!g_Renderer.m_SkipSubmit) {
|
||||
pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1,
|
||||
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->ffmodeldef->m_Indices);
|
||||
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
|
||||
}
|
||||
|
||||
// bump stats
|
||||
|
@ -46,18 +46,20 @@
|
||||
struct HWLModelDef : public CModelDefRPrivate
|
||||
{
|
||||
/// Indices are the same for all models, so share them
|
||||
u16* m_Indices;
|
||||
|
||||
VertexIndexArray m_IndexArray;
|
||||
|
||||
HWLModelDef(const CModelDefPtr& mdef);
|
||||
~HWLModelDef() { delete[] m_Indices; }
|
||||
};
|
||||
|
||||
|
||||
HWLModelDef::HWLModelDef(const CModelDefPtr& mdef)
|
||||
: m_IndexArray(GL_STATIC_DRAW)
|
||||
{
|
||||
m_Indices = new u16[mdef->GetNumFaces()*3];
|
||||
ModelRenderer::BuildIndices(mdef, m_Indices);
|
||||
m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
|
||||
m_IndexArray.Layout();
|
||||
ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
|
||||
m_IndexArray.Upload();
|
||||
m_IndexArray.FreeBackingStore();
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +75,7 @@ struct HWLModel
|
||||
/// UV is stored per-CModel in order to avoid space wastage due to alignment
|
||||
VertexArray::Attribute m_UV;
|
||||
|
||||
HWLModel() : m_Array(true) { }
|
||||
HWLModel() : m_Array(GL_DYNAMIC_DRAW) { }
|
||||
};
|
||||
|
||||
|
||||
@ -301,6 +303,8 @@ void HWLightingModelRenderer::RenderModel(int streamflags, CModel* model, void*
|
||||
u8* base = hwlmodel->m_Array.Bind();
|
||||
GLsizei stride = (GLsizei)hwlmodel->m_Array.GetStride();
|
||||
|
||||
u8* indexBase = m->hwlmodeldef->m_IndexArray.Bind();
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, stride, base + hwlmodel->m_Position.offset);
|
||||
if (streamflags & STREAM_COLOR)
|
||||
{
|
||||
@ -319,7 +323,7 @@ void HWLightingModelRenderer::RenderModel(int streamflags, CModel* model, void*
|
||||
|
||||
if (!g_Renderer.m_SkipSubmit) {
|
||||
pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1,
|
||||
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->hwlmodeldef->m_Indices);
|
||||
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
|
||||
}
|
||||
|
||||
// bump stats
|
||||
|
@ -54,16 +54,15 @@ struct IModelDef : public CModelDefRPrivate
|
||||
VertexArray::Attribute m_UV;
|
||||
|
||||
/// Indices are the same for all models, so share them
|
||||
u16* m_Indices;
|
||||
VertexIndexArray m_IndexArray;
|
||||
|
||||
|
||||
IModelDef(const CModelDefPtr& mdef);
|
||||
~IModelDef() { delete[] m_Indices; }
|
||||
};
|
||||
|
||||
|
||||
IModelDef::IModelDef(const CModelDefPtr& mdef)
|
||||
: m_Array(false)
|
||||
: m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
|
||||
{
|
||||
size_t numVertices = mdef->GetNumVertices();
|
||||
|
||||
@ -92,8 +91,11 @@ IModelDef::IModelDef(const CModelDefPtr& mdef)
|
||||
m_Array.Upload();
|
||||
m_Array.FreeBackingStore();
|
||||
|
||||
m_Indices = new u16[mdef->GetNumFaces()*3];
|
||||
ModelRenderer::BuildIndices(mdef, m_Indices);
|
||||
m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
|
||||
m_IndexArray.Layout();
|
||||
ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
|
||||
m_IndexArray.Upload();
|
||||
m_IndexArray.FreeBackingStore();
|
||||
}
|
||||
|
||||
|
||||
@ -105,6 +107,9 @@ struct InstancingModelRendererInternals
|
||||
/// Previously prepared modeldef
|
||||
IModelDef* imodeldef;
|
||||
|
||||
/// Index base for imodeldef
|
||||
u8* imodeldefIndexBase;
|
||||
|
||||
/// If true, primary color will only contain the diffuse term
|
||||
bool colorIsDiffuseOnly;
|
||||
|
||||
@ -243,6 +248,8 @@ void InstancingModelRenderer::PrepareModelDef(int streamflags, const CModelDefPt
|
||||
u8* base = m->imodeldef->m_Array.Bind();
|
||||
GLsizei stride = (GLsizei)m->imodeldef->m_Array.GetStride();
|
||||
|
||||
m->imodeldefIndexBase = m->imodeldef->m_IndexArray.Bind();
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, stride, base + m->imodeldef->m_Position.offset);
|
||||
if (streamflags & STREAM_COLOR)
|
||||
{
|
||||
@ -274,7 +281,7 @@ void InstancingModelRenderer::RenderModel(int streamflags, CModel* model, void*
|
||||
|
||||
if (!g_Renderer.m_SkipSubmit) {
|
||||
pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1,
|
||||
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldef->m_Indices);
|
||||
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase);
|
||||
}
|
||||
|
||||
// bump stats
|
||||
|
@ -161,7 +161,7 @@ void ModelRenderer::BuildUV(
|
||||
// Build default indices array.
|
||||
void ModelRenderer::BuildIndices(
|
||||
const CModelDefPtr& mdef,
|
||||
u16* Indices)
|
||||
const VertexArrayIterator<u16>& Indices)
|
||||
{
|
||||
size_t idxidx = 0;
|
||||
SModelFace* faces = mdef->GetFaces();
|
||||
|
@ -243,7 +243,7 @@ public:
|
||||
*/
|
||||
static void BuildIndices(
|
||||
const CModelDefPtr& mdef,
|
||||
u16* Indices);
|
||||
const VertexArrayIterator<u16>& Indices);
|
||||
};
|
||||
|
||||
|
||||
|
@ -283,7 +283,7 @@ void CPatchRData::BuildBlends()
|
||||
{
|
||||
// Construct vertex buffer
|
||||
|
||||
m_VBBlends = g_VBMan.Allocate(sizeof(SBlendVertex), m_BlendVertices.size(), true);
|
||||
m_VBBlends = g_VBMan.Allocate(sizeof(SBlendVertex), m_BlendVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
|
||||
m_VBBlends->m_Owner->UpdateChunkVertices(m_VBBlends, &m_BlendVertices[0]);
|
||||
|
||||
debug_assert(m_VBBlends->m_Index < 65536);
|
||||
@ -470,9 +470,9 @@ void CPatchRData::BuildVertices()
|
||||
}
|
||||
|
||||
// upload to vertex buffer
|
||||
if (!m_VBBase) {
|
||||
m_VBBase=g_VBMan.Allocate(sizeof(SBaseVertex),vsize*vsize,true);
|
||||
}
|
||||
if (!m_VBBase)
|
||||
m_VBBase = g_VBMan.Allocate(sizeof(SBaseVertex), vsize * vsize, GL_STATIC_DRAW, GL_ARRAY_BUFFER);
|
||||
|
||||
m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase,m_Vertices);
|
||||
}
|
||||
|
||||
@ -551,7 +551,7 @@ void CPatchRData::BuildSides()
|
||||
return;
|
||||
|
||||
if (!m_VBSides)
|
||||
m_VBSides = g_VBMan.Allocate(sizeof(SSideVertex), sideVertices.size(), true);
|
||||
m_VBSides = g_VBMan.Allocate(sizeof(SSideVertex), sideVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
|
||||
m_VBSides->m_Owner->UpdateChunkVertices(m_VBSides, &sideVertices[0]);
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include "renderer/TerrainOverlay.h"
|
||||
#include "renderer/TerrainRenderer.h"
|
||||
#include "renderer/TransparencyRenderer.h"
|
||||
#include "renderer/VertexBufferManager.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
|
||||
@ -104,6 +105,8 @@ private:
|
||||
Row_TerrainTris,
|
||||
Row_ModelTris,
|
||||
Row_BlendSplats,
|
||||
Row_VBReserved,
|
||||
Row_VBAllocated,
|
||||
|
||||
// Must be last to count number of rows
|
||||
NumberRows
|
||||
@ -175,6 +178,18 @@ CStr CRendererStatsTable::GetCellText(size_t row, size_t col)
|
||||
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_BlendSplats);
|
||||
return buf;
|
||||
|
||||
case Row_VBReserved:
|
||||
if (col == 0)
|
||||
return "VB bytes reserved";
|
||||
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)g_VBMan.GetBytesReserved());
|
||||
return buf;
|
||||
|
||||
case Row_VBAllocated:
|
||||
if (col == 0)
|
||||
return "VB bytes allocated";
|
||||
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)g_VBMan.GetBytesAllocated());
|
||||
return buf;
|
||||
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ struct PSModelDef : public CModelDefRPrivate
|
||||
};
|
||||
|
||||
PSModelDef::PSModelDef(const CModelDefPtr& mdef)
|
||||
: m_Array(false)
|
||||
: m_Array(GL_STATIC_DRAW)
|
||||
{
|
||||
m_UV.type = GL_FLOAT;
|
||||
m_UV.elems = 2;
|
||||
@ -113,7 +113,7 @@ struct PSModel
|
||||
};
|
||||
|
||||
PSModel::PSModel(CModel* model)
|
||||
: m_Model(model), m_Array(true)
|
||||
: m_Model(model), m_Array(GL_DYNAMIC_DRAW)
|
||||
{
|
||||
CModelDefPtr mdef = m_Model->GetModelDef();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib/bits.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "maths/Vector4D.h"
|
||||
@ -26,9 +27,10 @@
|
||||
#include "renderer/VertexBufferManager.h"
|
||||
|
||||
|
||||
VertexArray::VertexArray(bool dynamic)
|
||||
VertexArray::VertexArray(GLenum usage, GLenum target)
|
||||
{
|
||||
m_Dynamic = dynamic;
|
||||
m_Usage = usage;
|
||||
m_Target = target;
|
||||
m_NumVertices = 0;
|
||||
|
||||
m_VB = 0;
|
||||
@ -70,7 +72,7 @@ void VertexArray::SetNumVertices(size_t num)
|
||||
// Add vertex attributes like Position, Normal, UV
|
||||
void VertexArray::AddAttribute(Attribute* attr)
|
||||
{
|
||||
debug_assert((attr->type == GL_FLOAT || attr->type == GL_UNSIGNED_BYTE) && "Unsupported attribute type");
|
||||
debug_assert((attr->type == GL_FLOAT || attr->type == GL_UNSIGNED_SHORT || attr->type == GL_UNSIGNED_BYTE) && "Unsupported attribute type");
|
||||
debug_assert(attr->elems >= 1 && attr->elems <= 4);
|
||||
|
||||
attr->vertexArray = this;
|
||||
@ -133,6 +135,16 @@ VertexArrayIterator<SColor4ub> VertexArray::Attribute::GetIterator<SColor4ub>()
|
||||
return vertexArray->MakeIterator<SColor4ub>(this);
|
||||
}
|
||||
|
||||
template<>
|
||||
VertexArrayIterator<u16> VertexArray::Attribute::GetIterator<u16>() const
|
||||
{
|
||||
debug_assert(vertexArray);
|
||||
debug_assert(type == GL_UNSIGNED_SHORT);
|
||||
debug_assert(elems >= 1);
|
||||
|
||||
return vertexArray->MakeIterator<u16>(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static size_t RoundStride(size_t stride)
|
||||
@ -146,7 +158,7 @@ static size_t RoundStride(size_t stride)
|
||||
if (stride <= 16)
|
||||
return 16;
|
||||
|
||||
return (stride + 31) & ~31;
|
||||
return round_up(stride, (size_t)32);
|
||||
}
|
||||
|
||||
// Re-layout by assigning offsets on a first-come first-serve basis,
|
||||
@ -160,7 +172,7 @@ void VertexArray::Layout()
|
||||
|
||||
//debug_printf(L"Layouting VertexArray\n");
|
||||
|
||||
for(int idx = (int)m_Attributes.size()-1; idx >= 0; --idx)
|
||||
for (ssize_t idx = m_Attributes.size()-1; idx >= 0; --idx)
|
||||
{
|
||||
Attribute* attr = m_Attributes[idx];
|
||||
|
||||
@ -173,23 +185,31 @@ void VertexArray::Layout()
|
||||
case GL_UNSIGNED_BYTE:
|
||||
attrSize = sizeof(GLubyte);
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
attrSize = sizeof(GLushort);
|
||||
break;
|
||||
case GL_FLOAT:
|
||||
attrSize = sizeof(GLfloat);
|
||||
break;
|
||||
default:
|
||||
attrSize = 0;
|
||||
debug_warn(L"Bad AttributeInfo::Type"); break;
|
||||
debug_warn(L"Bad Attribute::type"); break;
|
||||
}
|
||||
|
||||
attrSize *= attr->elems;
|
||||
|
||||
attr->offset = m_Stride;
|
||||
m_Stride = (m_Stride + attrSize + 3) & ~3;
|
||||
|
||||
|
||||
m_Stride += attrSize;
|
||||
|
||||
if (m_Target == GL_ARRAY_BUFFER)
|
||||
m_Stride = round_up(m_Stride, (size_t)4);
|
||||
|
||||
//debug_printf(L"%i: offset: %u\n", idx, attr->offset);
|
||||
}
|
||||
|
||||
m_Stride = RoundStride(m_Stride);
|
||||
if (m_Target == GL_ARRAY_BUFFER)
|
||||
m_Stride = RoundStride(m_Stride);
|
||||
|
||||
//debug_printf(L"Stride: %u\n", m_Stride);
|
||||
|
||||
@ -205,7 +225,7 @@ void VertexArray::Upload()
|
||||
debug_assert(m_BackingStore);
|
||||
|
||||
if (!m_VB)
|
||||
m_VB = g_VBMan.Allocate(m_Stride, m_NumVertices, m_Dynamic);
|
||||
m_VB = g_VBMan.Allocate(m_Stride, m_NumVertices, m_Usage, m_Target);
|
||||
|
||||
if (!m_VB) // failed to allocate VBO
|
||||
return;
|
||||
@ -233,3 +253,17 @@ void VertexArray::FreeBackingStore()
|
||||
m_BackingStore = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
VertexIndexArray::VertexIndexArray(GLenum usage) :
|
||||
VertexArray(usage, GL_ELEMENT_ARRAY_BUFFER)
|
||||
{
|
||||
m_Attr.type = GL_UNSIGNED_SHORT;
|
||||
m_Attr.elems = 1;
|
||||
AddAttribute(&m_Attr);
|
||||
}
|
||||
|
||||
VertexArrayIterator<u16> VertexIndexArray::GetIterator() const
|
||||
{
|
||||
return m_Attr.GetIterator<u16>();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -116,8 +116,6 @@ private:
|
||||
// support with hardcoded vertex structures.
|
||||
// This class chooses the vertex layout at runtime, based on the attributes
|
||||
// that are actually needed.
|
||||
// Furthermore, it stores dynamic and static attributes in different
|
||||
// vertex buffers, so that needless re-uploads of static data is avoided.
|
||||
//
|
||||
// Note that this class will not allocate any OpenGL resources until one
|
||||
// of the Upload functions is called.
|
||||
@ -126,7 +124,7 @@ class VertexArray
|
||||
public:
|
||||
struct Attribute
|
||||
{
|
||||
// Data type. Currently supported: GL_FLOAT
|
||||
// Data type. Currently supported: GL_FLOAT, GL_UNSIGNED_BYTE
|
||||
GLenum type;
|
||||
// How many elements per vertex (e.g. 3 for RGB, 2 for UV)
|
||||
GLuint elems;
|
||||
@ -139,7 +137,7 @@ public:
|
||||
Attribute() : type(0), elems(0), offset(0), vertexArray(0) { }
|
||||
|
||||
// Get an iterator for the given attribute that initially points at the first vertex.
|
||||
// Supported types T: CVector3D, CVector4D, float[], SColor3ub, SColor4ub
|
||||
// Supported types T: CVector3D, CVector4D, float[2], SColor3ub, SColor4ub
|
||||
// This function verifies at runtime that the requested type T matches
|
||||
// the attribute definition passed to AddAttribute().
|
||||
template<typename T>
|
||||
@ -147,7 +145,7 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
VertexArray(bool dynamic);
|
||||
VertexArray(GLenum usage, GLenum target = GL_ARRAY_BUFFER);
|
||||
~VertexArray();
|
||||
|
||||
// Set the number of vertices stored in the array
|
||||
@ -163,7 +161,7 @@ public:
|
||||
// attributes.
|
||||
// All vertex data is lost when a vertex array is re-layouted.
|
||||
void Layout();
|
||||
// (Re-)Upload the static/dynamic attributes of the vertex array.
|
||||
// (Re-)Upload the attributes of the vertex array.
|
||||
void Upload();
|
||||
// Bind this array, returns the base address for calls to glVertexPointer etc.
|
||||
u8* Bind();
|
||||
@ -182,7 +180,8 @@ private:
|
||||
return VertexArrayIterator<T>(m_BackingStore + attr->offset, m_Stride);
|
||||
}
|
||||
|
||||
bool m_Dynamic;
|
||||
GLenum m_Usage;
|
||||
GLenum m_Target;
|
||||
size_t m_NumVertices;
|
||||
std::vector<Attribute*> m_Attributes;
|
||||
|
||||
@ -191,5 +190,21 @@ private:
|
||||
char* m_BackingStore;
|
||||
};
|
||||
|
||||
/**
|
||||
* A VertexArray that is specialised to handle 16-bit array indices.
|
||||
* Call Bind() and pass the return value to the indices parameter of
|
||||
* glDrawElements/glDrawRangeElements/glMultiDrawElements.
|
||||
* Use CVertexBuffer::Unbind() to unbind the array.
|
||||
*/
|
||||
class VertexIndexArray : public VertexArray
|
||||
{
|
||||
public:
|
||||
VertexIndexArray(GLenum usage);
|
||||
|
||||
VertexArrayIterator<u16> GetIterator() const;
|
||||
|
||||
private:
|
||||
Attribute m_Attr;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_VERTEXARRAY
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* encapsulation of VBOs with batching and sharing
|
||||
* encapsulation of VBOs with sharing
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
@ -28,59 +28,24 @@
|
||||
#include "VertexBufferManager.h"
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
ERROR_GROUP(Renderer);
|
||||
ERROR_TYPE(Renderer, VBOFailed);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// shared list of all free batch objects
|
||||
std::vector<CVertexBuffer::Batch *> CVertexBuffer::m_FreeBatches;
|
||||
// NOTE: This global variable is here (as opposed to in VertexBufferManager.cpp,
|
||||
// as would be logical) to make sure that m_FreeBatches is freed in the right
|
||||
// order relative to the VertexBufferManager
|
||||
CVertexBufferManager g_VBMan;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Call at shutdown to free memory
|
||||
void CVertexBuffer::Shutdown()
|
||||
{
|
||||
for(std::vector<Batch*>::iterator iter=m_FreeBatches.begin();iter!=m_FreeBatches.end();++iter)
|
||||
{
|
||||
delete *iter;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CVertexBuffer constructor
|
||||
CVertexBuffer::CVertexBuffer(size_t vertexSize,bool dynamic)
|
||||
: m_VertexSize(vertexSize), m_Handle(0), m_SysMem(0), m_Dynamic(dynamic)
|
||||
CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target)
|
||||
: m_VertexSize(vertexSize), m_Handle(0), m_SysMem(0), m_Usage(usage), m_Target(target)
|
||||
{
|
||||
size_t size = MAX_VB_SIZE_BYTES;
|
||||
|
||||
// allocate raw buffer
|
||||
if (g_Renderer.m_Caps.m_VBO) {
|
||||
|
||||
// TODO: Detect when VBO failed, then fall back to system memory
|
||||
// (and copy all old VBOs into there, because it needs to be
|
||||
// consistent).
|
||||
|
||||
// (PT: Disabled the VBOFailed test because it's not very useful at the
|
||||
// moment (it'll just cause the program to terminate, and I don't think
|
||||
// it has ever helped to discover any problems, and a later ogl_WarnIfError()
|
||||
// will tell us if there were any VBO issues anyway), and so it's a
|
||||
// waste of time to call glGetError so frequently.)
|
||||
// glGetError(); // clear the error state
|
||||
|
||||
if (g_Renderer.m_Caps.m_VBO)
|
||||
{
|
||||
pglGenBuffersARB(1, &m_Handle);
|
||||
pglBindBufferARB(GL_ARRAY_BUFFER_ARB, m_Handle);
|
||||
// if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
|
||||
|
||||
pglBufferDataARB(GL_ARRAY_BUFFER_ARB, size, 0, m_Dynamic ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB);
|
||||
// if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
|
||||
|
||||
pglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
|
||||
} else {
|
||||
m_SysMem=new u8[size];
|
||||
pglBindBufferARB(m_Target, m_Handle);
|
||||
pglBufferDataARB(m_Target, size, 0, m_Usage);
|
||||
pglBindBufferARB(m_Target, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SysMem = new u8[size];
|
||||
}
|
||||
|
||||
// store max/free vertex counts
|
||||
@ -98,15 +63,18 @@ CVertexBuffer::CVertexBuffer(size_t vertexSize,bool dynamic)
|
||||
// CVertexBuffer destructor
|
||||
CVertexBuffer::~CVertexBuffer()
|
||||
{
|
||||
if (m_Handle) {
|
||||
pglDeleteBuffersARB(1,&m_Handle);
|
||||
} else if (m_SysMem) {
|
||||
if (m_Handle)
|
||||
{
|
||||
pglDeleteBuffersARB(1, &m_Handle);
|
||||
}
|
||||
else if (m_SysMem)
|
||||
{
|
||||
delete[] m_SysMem;
|
||||
}
|
||||
|
||||
// janwas 2004-06-14: release freelist
|
||||
typedef std::list<VBChunk*>::iterator Iter;
|
||||
for(Iter iter=m_FreeList.begin();iter!=m_FreeList.end();++iter)
|
||||
for (Iter iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter)
|
||||
delete *iter;
|
||||
}
|
||||
|
||||
@ -114,13 +82,15 @@ CVertexBuffer::~CVertexBuffer()
|
||||
// Allocate: try to allocate a buffer of given number of vertices (each of
|
||||
// given size), with the given type, and using the given texture - return null
|
||||
// if no free chunks available
|
||||
CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize,size_t numVertices,bool dynamic)
|
||||
CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target)
|
||||
{
|
||||
// check this is the right kind of buffer
|
||||
if (dynamic!=m_Dynamic || vertexSize!=m_VertexSize) return 0;
|
||||
if (usage != m_Usage || target != m_Target || vertexSize != m_VertexSize)
|
||||
return 0;
|
||||
|
||||
// quick check there's enough vertices spare to allocate
|
||||
if (numVertices>m_FreeVertices) return 0;
|
||||
if (numVertices > m_FreeVertices)
|
||||
return 0;
|
||||
|
||||
// trawl free list looking for first free chunk with enough space
|
||||
VBChunk* chunk=0;
|
||||
@ -130,6 +100,7 @@ CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize,size_t numVert
|
||||
chunk=*iter;
|
||||
// remove this chunk from the free list
|
||||
m_FreeList.erase(iter);
|
||||
m_FreeVertices -= chunk->m_Count;
|
||||
// no need to search further ..
|
||||
break;
|
||||
}
|
||||
@ -142,16 +113,17 @@ CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize,size_t numVert
|
||||
|
||||
// split chunk into two; - allocate a new chunk using all unused vertices in the
|
||||
// found chunk, and add it to the free list
|
||||
if (chunk->m_Count > numVertices) {
|
||||
VBChunk* newchunk=new VBChunk;
|
||||
newchunk->m_Owner=this;
|
||||
newchunk->m_Count=chunk->m_Count-numVertices;
|
||||
newchunk->m_Index=chunk->m_Index+numVertices;
|
||||
if (chunk->m_Count > numVertices)
|
||||
{
|
||||
VBChunk* newchunk = new VBChunk;
|
||||
newchunk->m_Owner = this;
|
||||
newchunk->m_Count = chunk->m_Count - numVertices;
|
||||
newchunk->m_Index = chunk->m_Index + numVertices;
|
||||
m_FreeList.push_front(newchunk);
|
||||
m_FreeVertices += newchunk->m_Count;
|
||||
|
||||
// resize given chunk, resize total available free vertices
|
||||
chunk->m_Count=numVertices;
|
||||
m_FreeVertices-=numVertices;
|
||||
// resize given chunk
|
||||
chunk->m_Count = numVertices;
|
||||
}
|
||||
|
||||
// return found chunk
|
||||
@ -166,63 +138,22 @@ void CVertexBuffer::Release(VBChunk* chunk)
|
||||
// TODO, RC - need to merge available chunks where possible to avoid
|
||||
// excessive fragmentation of vertex buffer space
|
||||
m_FreeList.push_front(chunk);
|
||||
m_FreeVertices+=chunk->m_Count;
|
||||
m_FreeVertices += chunk->m_Count;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ClearBatchIndices: clear lists of all batches
|
||||
void CVertexBuffer::ClearBatchIndices()
|
||||
{
|
||||
for (size_t i=0;i<m_Batches.size();i++) {
|
||||
m_Batches[i]->m_IndexData.clear();
|
||||
m_FreeBatches.push_back(m_Batches[i]);
|
||||
}
|
||||
m_Batches.clear();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AppendBatch: add a batch to the render list for this buffer
|
||||
void CVertexBuffer::AppendBatch(VBChunk* UNUSED(chunk),Handle texture,size_t numIndices,u16* indices)
|
||||
{
|
||||
// try and find a batch using this texture
|
||||
size_t i;
|
||||
Batch* batch=0;
|
||||
for (i=0;i<m_Batches.size();++i) {
|
||||
if (m_Batches[i]->m_Texture==texture) {
|
||||
batch=m_Batches[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!batch) {
|
||||
if (m_FreeBatches.size()) {
|
||||
batch=m_FreeBatches.back();
|
||||
m_FreeBatches.pop_back();
|
||||
} else {
|
||||
batch=new Batch();
|
||||
}
|
||||
m_Batches.push_back(batch);
|
||||
batch->m_Texture=texture;
|
||||
}
|
||||
|
||||
// resize the chunk's batch to fit its indices
|
||||
batch->m_IndexData.push_back(std::pair<size_t,u16*>(numIndices,indices));
|
||||
// memcpy(&batch->m_Indices[0]+cursize,indices,sizeof(u16)*numIndices);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UpdateChunkVertices: update vertex data for given chunk
|
||||
void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk,void* data)
|
||||
{
|
||||
if (g_Renderer.m_Caps.m_VBO) {
|
||||
if (g_Renderer.m_Caps.m_VBO)
|
||||
{
|
||||
debug_assert(m_Handle);
|
||||
// glGetError(); // clear the error state
|
||||
pglBindBufferARB(GL_ARRAY_BUFFER_ARB, m_Handle);
|
||||
pglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize, data);
|
||||
pglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
// if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
|
||||
} else {
|
||||
pglBindBufferARB(m_Target, m_Handle);
|
||||
pglBufferSubDataARB(m_Target, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize, data);
|
||||
pglBindBufferARB(m_Target, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_assert(m_SysMem);
|
||||
memcpy(m_SysMem + chunk->m_Index * m_VertexSize, data, chunk->m_Count * m_VertexSize);
|
||||
}
|
||||
@ -233,20 +164,32 @@ void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk,void* data)
|
||||
// to glVertexPointer ( + etc) calls
|
||||
u8* CVertexBuffer::Bind()
|
||||
{
|
||||
u8* base;
|
||||
|
||||
if (g_Renderer.m_Caps.m_VBO) {
|
||||
pglBindBufferARB(GL_ARRAY_BUFFER_ARB,m_Handle);
|
||||
base=(u8*) 0;
|
||||
} else {
|
||||
base=(u8*) m_SysMem;
|
||||
if (g_Renderer.m_Caps.m_VBO)
|
||||
{
|
||||
pglBindBufferARB(m_Target, m_Handle);
|
||||
return (u8*)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_SysMem;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
void CVertexBuffer::Unbind()
|
||||
{
|
||||
if (g_Renderer.m_Caps.m_VBO) {
|
||||
pglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
if (g_Renderer.m_Caps.m_VBO)
|
||||
{
|
||||
pglBindBufferARB(GL_ARRAY_BUFFER, 0);
|
||||
pglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
size_t CVertexBuffer::GetBytesReserved() const
|
||||
{
|
||||
return MAX_VB_SIZE_BYTES;
|
||||
}
|
||||
|
||||
size_t CVertexBuffer::GetBytesAllocated() const
|
||||
{
|
||||
return (m_MaxVertices - m_FreeVertices) * m_VertexSize;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -30,25 +30,12 @@
|
||||
// absolute maximum (bytewise) size of each GL vertex buffer object
|
||||
#define MAX_VB_SIZE_BYTES (512*1024)
|
||||
|
||||
template <typename T>
|
||||
struct ctor_dtor_logger;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CVertexBuffer: encapsulation of ARB_vertex_buffer_object, also supplying
|
||||
// some additional functionality for batching and sharing buffers between
|
||||
// multiple objects
|
||||
// some additional functionality for sharing buffers between multiple objects
|
||||
class CVertexBuffer
|
||||
{
|
||||
public:
|
||||
// Batch: batch definition - defines indices into the VB to use when rendering,
|
||||
// and the texture used when doing so
|
||||
struct Batch {
|
||||
// list of indices into the vertex buffer of primitives within the batch
|
||||
std::vector<std::pair<size_t,u16*> > m_IndexData;
|
||||
// texture to apply when rendering batch
|
||||
Handle m_Texture;
|
||||
};
|
||||
|
||||
// VBChunk: describes a portion of this vertex buffer
|
||||
struct VBChunk
|
||||
{
|
||||
@ -62,7 +49,7 @@ public:
|
||||
|
||||
public:
|
||||
// constructor, destructor
|
||||
CVertexBuffer(size_t vertexSize, bool dynamic);
|
||||
CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target);
|
||||
~CVertexBuffer();
|
||||
|
||||
// bind to this buffer; return pointer to address required as parameter
|
||||
@ -72,36 +59,25 @@ public:
|
||||
// unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it
|
||||
static void Unbind();
|
||||
|
||||
// clear lists of all batches
|
||||
void ClearBatchIndices();
|
||||
|
||||
// add a batch to the render list for this buffer
|
||||
void AppendBatch(VBChunk* chunk,Handle texture,size_t numIndices,u16* indices);
|
||||
|
||||
// update vertex data for given chunk
|
||||
void UpdateChunkVertices(VBChunk* chunk,void* data);
|
||||
|
||||
// return this VBs batch list
|
||||
const std::vector<Batch*>& GetBatches() const { return m_Batches; }
|
||||
void UpdateChunkVertices(VBChunk* chunk, void* data);
|
||||
|
||||
size_t GetVertexSize() const { return m_VertexSize; }
|
||||
|
||||
// free memory
|
||||
static void Shutdown();
|
||||
size_t GetBytesReserved() const;
|
||||
size_t GetBytesAllocated() const;
|
||||
|
||||
protected:
|
||||
friend class CVertexBufferManager; // allow allocate only via CVertexBufferManager
|
||||
|
||||
// try to allocate a buffer of given number of vertices (each of given size),
|
||||
// and with the given type - return null if no free chunks available
|
||||
VBChunk* Allocate(size_t vertexSize,size_t numVertices,bool dynamic);
|
||||
VBChunk* Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target);
|
||||
// return given chunk to this buffer
|
||||
void Release(VBChunk* chunk);
|
||||
|
||||
|
||||
private:
|
||||
// set of all possible batches that can be used by this VB
|
||||
std::vector<Batch*> m_Batches;
|
||||
// vertex size of this vertex buffer
|
||||
size_t m_VertexSize;
|
||||
// number of vertices of above size in this buffer
|
||||
@ -114,11 +90,10 @@ private:
|
||||
GLuint m_Handle;
|
||||
// raw system memory for systems not supporting VBOs
|
||||
u8* m_SysMem;
|
||||
// type of the buffer - dynamic?
|
||||
bool m_Dynamic;
|
||||
|
||||
// list of all spare batches, shared between all vbs
|
||||
static std::vector<Batch *> m_FreeBatches;
|
||||
// usage type of the buffer (GL_STATIC_DRAW etc)
|
||||
GLenum m_Usage;
|
||||
// buffer target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER)
|
||||
GLenum m_Target;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -21,10 +21,12 @@
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib/ogl.h"
|
||||
#include "VertexBufferManager.h"
|
||||
|
||||
#include "lib/ogl.h"
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
CVertexBufferManager g_VBMan;
|
||||
|
||||
// janwas 2004-06-14: added dtor
|
||||
|
||||
@ -39,10 +41,9 @@ CVertexBufferManager::~CVertexBufferManager()
|
||||
void CVertexBufferManager::Shutdown()
|
||||
{
|
||||
typedef std::list<CVertexBuffer*>::iterator Iter;
|
||||
for (Iter iter=m_Buffers.begin();iter!=m_Buffers.end();++iter)
|
||||
for (Iter iter = m_Buffers.begin(); iter != m_Buffers.end(); ++iter)
|
||||
delete *iter;
|
||||
|
||||
CVertexBuffer::Shutdown();
|
||||
m_Buffers.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -50,10 +51,14 @@ void CVertexBufferManager::Shutdown()
|
||||
// Allocate: try to allocate a buffer of given number of vertices (each of
|
||||
// given size), with the given type, and using the given texture - return null
|
||||
// if no free chunks available
|
||||
CVertexBuffer::VBChunk* CVertexBufferManager::Allocate(size_t vertexSize, size_t numVertices, bool dynamic)
|
||||
CVertexBuffer::VBChunk* CVertexBufferManager::Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target)
|
||||
{
|
||||
CVertexBuffer::VBChunk* result=0;
|
||||
|
||||
debug_assert(usage == GL_STREAM_DRAW || usage == GL_STATIC_DRAW || usage == GL_DYNAMIC_DRAW);
|
||||
|
||||
debug_assert(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER);
|
||||
|
||||
// TODO, RC - run some sanity checks on allocation request
|
||||
|
||||
// iterate through all existing buffers testing for one that'll
|
||||
@ -61,15 +66,15 @@ CVertexBuffer::VBChunk* CVertexBufferManager::Allocate(size_t vertexSize, size_t
|
||||
typedef std::list<CVertexBuffer*>::iterator Iter;
|
||||
for (Iter iter = m_Buffers.begin(); iter != m_Buffers.end(); ++iter) {
|
||||
CVertexBuffer* buffer = *iter;
|
||||
result = buffer->Allocate(vertexSize, numVertices, dynamic);
|
||||
result = buffer->Allocate(vertexSize, numVertices, usage, target);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
// got this far; need to allocate a new buffer
|
||||
CVertexBuffer* buffer = new CVertexBuffer(vertexSize, dynamic);
|
||||
CVertexBuffer* buffer = new CVertexBuffer(vertexSize, usage, target);
|
||||
m_Buffers.push_front(buffer);
|
||||
result = buffer->Allocate(vertexSize, numVertices, dynamic);
|
||||
result = buffer->Allocate(vertexSize, numVertices, usage, target);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@ -87,13 +92,25 @@ void CVertexBufferManager::Release(CVertexBuffer::VBChunk* chunk)
|
||||
chunk->m_Owner->Release(chunk);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ClearBatchIndices: empty out the batch lists of all vertex buffers
|
||||
void CVertexBufferManager::ClearBatchIndices()
|
||||
|
||||
size_t CVertexBufferManager::GetBytesReserved()
|
||||
{
|
||||
size_t total = 0;
|
||||
|
||||
typedef std::list<CVertexBuffer*>::iterator Iter;
|
||||
for (Iter iter=m_Buffers.begin();iter!=m_Buffers.end();++iter) {
|
||||
CVertexBuffer* buffer=*iter;
|
||||
buffer->ClearBatchIndices();
|
||||
}
|
||||
for (Iter iter = m_Buffers.begin(); iter != m_Buffers.end(); ++iter)
|
||||
total += (*iter)->GetBytesReserved();
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t CVertexBufferManager::GetBytesAllocated()
|
||||
{
|
||||
size_t total = 0;
|
||||
|
||||
typedef std::list<CVertexBuffer*>::iterator Iter;
|
||||
for (Iter iter = m_Buffers.begin(); iter != m_Buffers.end(); ++iter)
|
||||
total += (*iter)->GetBytesAllocated();
|
||||
|
||||
return total;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -36,19 +36,24 @@ public:
|
||||
// Explicit shutdown of the vertex buffer subsystem
|
||||
void Shutdown();
|
||||
|
||||
// try to allocate a buffer of given number of vertices (each of given size),
|
||||
// and with the given type - return null if no free chunks available
|
||||
CVertexBuffer::VBChunk* Allocate(size_t vertexSize,size_t numVertices,bool dynamic);
|
||||
/**
|
||||
* Try to allocate a buffer of given number of vertices (each of given size),
|
||||
* and with the given type.
|
||||
* @param usage typically GL_STATIC_DRAW or GL_DYNAMIC_DRAW
|
||||
* @param target typically GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER
|
||||
* @return chunk, or NULL if no free chunks available
|
||||
*/
|
||||
CVertexBuffer::VBChunk* Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target);
|
||||
|
||||
// return given chunk to it's owner
|
||||
// return given chunk to its owner
|
||||
void Release(CVertexBuffer::VBChunk* chunk);
|
||||
|
||||
// empty out the batch lists of all vertex buffers
|
||||
void ClearBatchIndices();
|
||||
|
||||
// return list of all buffers
|
||||
const std::list<CVertexBuffer*>& GetBufferList() const { return m_Buffers; }
|
||||
|
||||
size_t GetBytesReserved();
|
||||
size_t GetBytesAllocated();
|
||||
|
||||
private:
|
||||
// list of all known vertex buffers
|
||||
std::list<CVertexBuffer*> m_Buffers;
|
||||
@ -56,5 +61,4 @@ private:
|
||||
|
||||
extern CVertexBufferManager g_VBMan;
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user