- use separate vertex buffers per model to avoid large memory usage peaks. Also delete the geometry data for the models once it has been copied into the vertex buffer.

This commit is contained in:
Christoph Oelckers 2014-10-24 11:43:25 +02:00
parent bca47bb9bc
commit e5cd90f323
8 changed files with 287 additions and 107 deletions

View file

@ -197,13 +197,16 @@ class FModelVertexBuffer : public FVertexBuffer
unsigned int ibo_id;
public:
// these are public because it's the models having to fill them in.
TArray<FModelVertex> vbo_shadowdata; // this is kept around for interpolating on GL 2.0
TArray<unsigned int> ibo_shadowdata; // this is kept around for interpolating on GL 2.0
FModelVertexBuffer();
FModelVertexBuffer(bool needindex);
~FModelVertexBuffer();
FModelVertex *LockVertexBuffer(unsigned int size);
void UnlockVertexBuffer();
unsigned int *LockIndexBuffer(unsigned int size);
void UnlockIndexBuffer();
unsigned int SetupFrame(unsigned int frame1, unsigned int frame2);
};

View file

@ -93,35 +93,44 @@ public:
DeletingModelArray Models;
//===========================================================================
//
//
//
//===========================================================================
FModelVertexBuffer::FModelVertexBuffer()
void gl_LoadModels()
{
ibo_id = 0;
glGenBuffers(1, &ibo_id);
//for (unsigned i = 1; i < Models.Size(); i++)
for (int i = Models.Size() - 1; i >= 0; i--)
{
Models[i]->BuildVertexBuffer(this);
Models[i]->BuildVertexBuffer();
}
}
//===========================================================================
//
//
//
//===========================================================================
FModelVertexBuffer::FModelVertexBuffer(bool needindex)
{
glBindVertexArray(vao_id);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glBufferData(GL_ARRAY_BUFFER,vbo_shadowdata.Size() * sizeof(FModelVertex), &vbo_shadowdata[0], GL_STATIC_DRAW);
ibo_id = 0;
if (needindex)
{
glGenBuffers(1, &ibo_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,ibo_shadowdata.Size() * sizeof(unsigned int), &ibo_shadowdata[0], GL_STATIC_DRAW);
}
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glEnableVertexAttribArray(VATTR_VERTEX);
glEnableVertexAttribArray(VATTR_TEXCOORD);
glEnableVertexAttribArray(VATTR_VERTEX2);
glBindVertexArray(0);
}
//===========================================================================
//
//
//
//===========================================================================
FModelVertexBuffer::~FModelVertexBuffer()
{
if (ibo_id != 0)
@ -130,6 +139,63 @@ FModelVertexBuffer::~FModelVertexBuffer()
}
}
//===========================================================================
//
//
//
//===========================================================================
FModelVertex *FModelVertexBuffer::LockVertexBuffer(unsigned int size)
{
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glBufferData(GL_ARRAY_BUFFER, size * sizeof(FModelVertex), NULL, GL_STATIC_DRAW);
return (FModelVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, size * sizeof(FModelVertex), GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_BUFFER_BIT);
}
//===========================================================================
//
//
//
//===========================================================================
void FModelVertexBuffer::UnlockVertexBuffer()
{
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glUnmapBuffer(GL_ARRAY_BUFFER);
}
//===========================================================================
//
//
//
//===========================================================================
unsigned int *FModelVertexBuffer::LockIndexBuffer(unsigned int size)
{
if (ibo_id != 0)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size * sizeof(unsigned int), NULL, GL_STATIC_DRAW);
return (unsigned int*)glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, size * sizeof(unsigned int), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
else
{
return NULL;
}
}
//===========================================================================
//
//
//
//===========================================================================
void FModelVertexBuffer::UnlockIndexBuffer()
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
}
//===========================================================================
//
@ -147,6 +213,16 @@ unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int fr
return frame1;
}
//===========================================================================
//
// FModel::~FModel
//
//===========================================================================
FModel::~FModel()
{
if (mVBuf != NULL) delete mVBuf;
}
@ -293,7 +369,7 @@ static FModel * FindModel(const char * path, const char * modelfile)
return NULL;
}
}
// The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized
model->mFileName = fullname;
Models.Push(model);
return model;
@ -734,7 +810,8 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf,
if (mdl!=NULL)
{
gl_RenderState.SetVertexBuffer(GLRenderer->mModelVBO);
mdl->BuildVertexBuffer();
gl_RenderState.SetVertexBuffer(mdl->mVBuf);
if ( smfNext && smf->modelframes[i] != smfNext->modelframes[i] )
mdl->RenderFrame(smf->skins[i], smf->modelframes[i], smfNext->modelframes[i], inter, translation);

View file

@ -24,16 +24,19 @@ FTexture * LoadSkin(const char * path, const char * fn);
class FModel
{
public:
FModel() { }
virtual ~FModel() { }
FModel()
{
mVBuf = NULL;
}
virtual ~FModel();
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0;
virtual int FindFrame(const char * name) = 0;
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0;
virtual void BuildVertexBuffer(FModelVertexBuffer *buf) = 0;
virtual void BuildVertexBuffer() = 0;
FModelVertexBuffer *mVBuf;
FString mFileName;
};
@ -139,7 +142,8 @@ public:
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
virtual int FindFrame(const char * name);
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
virtual void BuildVertexBuffer(FModelVertexBuffer *buf);
void BuildVertexBuffer();
void CleanTempData();
};
@ -201,11 +205,19 @@ class FMD3Model : public FModel
}
~MD3Surface()
{
if (skins) delete [] skins;
CleanTempData();
}
void CleanTempData()
{
if (tris) delete [] tris;
if (vertices) delete [] vertices;
if (texcoords) delete [] texcoords;
if (skins) delete [] skins;
tris = NULL;
vertices = NULL;
texcoords = NULL;
}
};
@ -231,7 +243,7 @@ public:
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
virtual int FindFrame(const char * name);
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
virtual void BuildVertexBuffer(FModelVertexBuffer *buf);
void BuildVertexBuffer();
};
struct FVoxelVertexHash
@ -268,11 +280,10 @@ class FVoxelModel : public FModel
protected:
FVoxel *mVoxel;
bool mOwningVoxel; // if created through MODELDEF deleting this object must also delete the voxel object
FTexture *mPalette;
unsigned int mNumIndices;
TArray<FModelVertex> mVertices;
TArray<unsigned int> mIndices;
FTexture *mPalette;
unsigned int vindex;
unsigned int iindex;
void MakeSlabPolys(int x, int y, kvxslab_t *voxptr, FVoxelMap &check);
void AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3, int x4, int y4, int z4, BYTE color, FVoxelMap &check);
@ -286,7 +297,7 @@ public:
virtual int FindFrame(const char * name);
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
FTexture *GetPaletteTexture() const { return mPalette; }
void BuildVertexBuffer(FModelVertexBuffer *buf);
void BuildVertexBuffer();
};

View file

@ -206,45 +206,76 @@ bool FDMDModel::Load(const char * path, int, const char * buffer, int length)
}
//===========================================================================
//
//
//
//===========================================================================
FDMDModel::~FDMDModel()
{
int i;
CleanTempData();
// clean up
if (skins != NULL)
{
// skins are managed by the texture manager so they must not be deleted here.
delete [] skins;
if (skins != NULL) delete [] skins;
if (frames != NULL) delete [] frames;
}
//===========================================================================
//
// Deletes everything that's no longer needed after building the vertex buffer
//
//===========================================================================
void FDMDModel::CleanTempData()
{
int i;
if (frames != NULL)
{
for (i=0;i<info.numFrames;i++)
{
delete [] frames[i].vertices;
delete [] frames[i].normals;
if (frames[i].vertices != NULL) delete [] frames[i].vertices;
if (frames[i].normals != NULL) delete [] frames[i].normals;
frames[i].vertices = NULL;
frames[i].normals = NULL;
}
delete [] frames;
}
for(i = 0; i < info.numLODs; i++)
{
if (lods[i].triangles != NULL) delete[] lods[i].triangles;
lods[i].triangles = NULL;
}
if (texCoords != NULL) delete[] texCoords;
texCoords = NULL;
}
//===========================================================================
//
//
//
//===========================================================================
void FDMDModel::BuildVertexBuffer(FModelVertexBuffer *buf)
void FDMDModel::BuildVertexBuffer()
{
if (mVBuf == NULL)
{
int VertexBufferSize = info.numFrames * lodInfo[0].numTriangles * 3;
unsigned int vindex = 0;
mVBuf = new FModelVertexBuffer(false);
FModelVertex *vertptr = mVBuf->LockVertexBuffer(VertexBufferSize);
for (int i = 0; i < info.numFrames; i++)
{
ModelFrame *frame = &frames[i];
DMDModelVertex *vert = frame->vertices;
DMDModelVertex *norm = frame->normals;
frame->vindex = buf->vbo_shadowdata.Size();
frame->vindex = vindex;
FTriangle *tri = lods[0].triangles;
@ -253,18 +284,19 @@ void FDMDModel::BuildVertexBuffer(FModelVertexBuffer *buf)
{
for (int j = 0; j < 3; j++)
{
FModelVertex bvert;
int ti = tri->textureIndices[j];
int vi = tri->vertexIndices[j];
bvert.Set(vert[vi].xyz[0], vert[vi].xyz[1], vert[vi].xyz[2], (float)texCoords[ti].s /info.skinWidth, (float)texCoords[ti].t/info.skinHeight);
bvert.SetNormal(norm[vi].xyz[0], norm[vi].xyz[1], norm[vi].xyz[2]);
buf->vbo_shadowdata.Push(bvert);
FModelVertex *bvert = &vertptr[vindex++];
bvert->Set(vert[vi].xyz[0], vert[vi].xyz[1], vert[vi].xyz[2], (float)texCoords[ti].s / info.skinWidth, (float)texCoords[ti].t / info.skinHeight);
bvert->SetNormal(norm[vi].xyz[0], norm[vi].xyz[1], norm[vi].xyz[2]);
}
tri++;
}
}
mVBuf->UnlockVertexBuffer();
CleanTempData();
}
}
@ -307,7 +339,7 @@ void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
gl_RenderState.SetInterpolationFactor((float)inter);
gl_RenderState.Apply();
GLRenderer->mModelVBO->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex);
mVBuf->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex);
glDrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3);
gl_RenderState.SetInterpolationFactor(0.f);
}

View file

@ -207,37 +207,72 @@ bool FMD3Model::Load(const char * path, int, const char * buffer, int length)
return true;
}
void FMD3Model::BuildVertexBuffer(FModelVertexBuffer *buf)
//===========================================================================
//
//
//
//===========================================================================
void FMD3Model::BuildVertexBuffer()
{
if (mVBuf == NULL)
{
unsigned int vbufsize = 0;
unsigned int ibufsize = 0;
for (int i = 0; i < numSurfaces; i++)
{
MD3Surface * surf = &surfaces[i];
vbufsize += numFrames * surf->numVertices;
ibufsize += 3 * surf->numTriangles;
}
mVBuf = new FModelVertexBuffer(true);
FModelVertex *vertptr = mVBuf->LockVertexBuffer(vbufsize);
unsigned int *indxptr = mVBuf->LockIndexBuffer(ibufsize);
assert(vertptr != NULL && indxptr != NULL);
unsigned int vindex = 0, iindex = 0;
for (int i = 0; i < numSurfaces; i++)
{
MD3Surface * surf = &surfaces[i];
surf->vindex = buf->vbo_shadowdata.Size();
surf->iindex = buf->ibo_shadowdata.Size();
surf->vindex = vindex;
surf->iindex = iindex;
for (int j = 0; j < numFrames * surf->numVertices; j++)
{
MD3Vertex* vert = surf->vertices + j;
FModelVertex bvert;
FModelVertex *bvert = &vertptr[vindex++];
int tc = j % surf->numVertices;
bvert.Set(vert->x, vert->z, vert->y, surf->texcoords[tc].s, surf->texcoords[tc].t);
bvert.SetNormal(vert->nx, vert->nz, vert->ny);
buf->vbo_shadowdata.Push(bvert);
bvert->Set(vert->x, vert->z, vert->y, surf->texcoords[tc].s, surf->texcoords[tc].t);
bvert->SetNormal(vert->nx, vert->nz, vert->ny);
}
for (int k = 0; k < surf->numTriangles; k++)
{
for (int l = 0; l < 3; l++)
{
buf->ibo_shadowdata.Push(surf->tris[k].VertIndex[l]);
indxptr[iindex++] = surf->tris[k].VertIndex[l];
}
}
surf->CleanTempData();
}
mVBuf->UnlockVertexBuffer();
mVBuf->UnlockIndexBuffer();
}
}
//===========================================================================
//
//
//
//===========================================================================
int FMD3Model::FindFrame(const char * name)
{
for (int i=0;i<numFrames;i++)
@ -247,6 +282,12 @@ int FMD3Model::FindFrame(const char * name)
return -1;
}
//===========================================================================
//
//
//
//===========================================================================
void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double inter, int translation)
{
if (frameno>=numFrames || frameno2>=numFrames) return;
@ -271,12 +312,18 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
gl_RenderState.Apply();
GLRenderer->mModelVBO->SetupFrame(surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices);
mVBuf->SetupFrame(surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices);
glDrawElements(GL_TRIANGLES, surf->numTriangles * 3, GL_UNSIGNED_INT, (void*)(intptr_t)(surf->iindex * sizeof(unsigned int)));
}
gl_RenderState.SetInterpolationFactor(0.f);
}
//===========================================================================
//
//
//
//===========================================================================
FMD3Model::~FMD3Model()
{
if (frames) delete [] frames;

View file

@ -214,8 +214,6 @@ FVoxelModel::FVoxelModel(FVoxel *voxel, bool owned)
mVoxel = voxel;
mOwningVoxel = owned;
mPalette = new FVoxelTexture(voxel);
Initialize();
iindex = vindex = UINT_MAX;
}
//===========================================================================
@ -231,24 +229,6 @@ FVoxelModel::~FVoxelModel()
}
//===========================================================================
//
//
//
//===========================================================================
void FVoxelModel::BuildVertexBuffer(FModelVertexBuffer *buf)
{
vindex = buf->vbo_shadowdata.Size();
iindex = buf->ibo_shadowdata.Size();
FModelVertex *mv = &buf->vbo_shadowdata[buf->vbo_shadowdata.Reserve(mVertices.Size())];
unsigned int *mi = &buf->ibo_shadowdata[buf->ibo_shadowdata.Reserve(mIndices.Size())];
memcpy(mv, &mVertices[0], sizeof(FModelVertex)* mVertices.Size());
memcpy(mi, &mIndices[0], sizeof(unsigned int)* mIndices.Size());
}
//===========================================================================
//
//
@ -386,6 +366,37 @@ void FVoxelModel::Initialize()
}
}
//===========================================================================
//
//
//
//===========================================================================
void FVoxelModel::BuildVertexBuffer()
{
if (mVBuf == NULL)
{
Initialize();
mVBuf = new FModelVertexBuffer(true);
FModelVertex *vertptr = mVBuf->LockVertexBuffer(mVertices.Size());
unsigned int *indxptr = mVBuf->LockIndexBuffer(mIndices.Size());
memcpy(vertptr, &mVertices[0], sizeof(FModelVertex)* mVertices.Size());
memcpy(indxptr, &mIndices[0], sizeof(unsigned int)* mIndices.Size());
mVBuf->UnlockVertexBuffer();
mVBuf->UnlockIndexBuffer();
// delete our temporary buffers
mVertices.Clear();
mIndices.Clear();
mVertices.ShrinkToFit();
mIndices.ShrinkToFit();
}
}
//===========================================================================
//
//
@ -420,7 +431,7 @@ void FVoxelModel::RenderFrame(FTexture * skin, int frame, int frame2, double int
gl_RenderState.SetMaterial(tex, CLAMP_NOFILTER, translation, -1, false);
gl_RenderState.Apply();
GLRenderer->mModelVBO->SetupFrame(vindex, vindex);
glDrawElements(GL_TRIANGLES, mIndices.Size(), GL_UNSIGNED_INT, (void*)(intptr_t)(iindex * sizeof(unsigned int)));
mVBuf->SetupFrame(0, 0);
glDrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, (void*)(intptr_t)0);
}

View file

@ -99,6 +99,8 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
mLights = NULL;
}
void gl_LoadModels();
void FGLRenderer::Initialize()
{
glpart2 = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/glpart2.png"), FTexture::TEX_MiscPatch);
@ -107,13 +109,13 @@ void FGLRenderer::Initialize()
mVBO = new FFlatVertexBuffer;
mSkyVBO = new FSkyVertexBuffer;
mModelVBO = new FModelVertexBuffer;
mLights = new FLightBuffer();
gl_RenderState.SetVertexBuffer(mVBO);
mFBID = 0;
SetupLevel();
mShaderManager = new FShaderManager;
mSamplerManager = new FSamplerManager;
gl_LoadModels();
}
FGLRenderer::~FGLRenderer()
@ -123,7 +125,6 @@ FGLRenderer::~FGLRenderer()
if (mShaderManager != NULL) delete mShaderManager;
if (mSamplerManager != NULL) delete mSamplerManager;
if (mVBO != NULL) delete mVBO;
if (mModelVBO) delete mModelVBO;
if (mSkyVBO != NULL) delete mSkyVBO;
if (mLights != NULL) delete mLights;
if (glpart2) delete glpart2;

View file

@ -10,7 +10,6 @@ struct particle_t;
class FCanvasTexture;
class FFlatVertexBuffer;
class FSkyVertexBuffer;
class FModelVertexBuffer;
class OpenGLFrameBuffer;
struct FDrawInfo;
struct pspdef_t;
@ -72,7 +71,6 @@ public:
FFlatVertexBuffer *mVBO;
FSkyVertexBuffer *mSkyVBO;
FModelVertexBuffer *mModelVBO;
FLightBuffer *mLights;