Fixes to avoid needless re-buffering in PostLoad + fix for a crash/memory leak when changing areas

This commit is contained in:
parax0 2016-02-10 18:49:56 -07:00
parent 7bd97f0fce
commit 3296948bea
4 changed files with 94 additions and 87 deletions

View File

@ -31,48 +31,54 @@ CModel::~CModel()
void CModel::BufferGL() void CModel::BufferGL()
{ {
mVBO.Clear(); if (!mBuffered)
mSubmeshIndexBuffers.clear();
mSubmeshIndexBuffers.resize(mSurfaces.size());
for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
{ {
SSurface *pSurf = mSurfaces[iSurf]; mVBO.Clear();
mSurfaceIndexBuffers.clear();
u16 VBOStartOffset = (u16) mVBO.Size(); mSurfaceIndexBuffers.resize(mSurfaces.size());
mVBO.Reserve((u16) pSurf->VertexCount);
for (u32 iPrim = 0; iPrim < pSurf->Primitives.size(); iPrim++) for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
{ {
SSurface::SPrimitive *pPrim = &pSurf->Primitives[iPrim]; SSurface *pSurf = mSurfaces[iSurf];
CIndexBuffer *pIBO = InternalGetIBO(iSurf, pPrim->Type);
pIBO->Reserve(pPrim->Vertices.size() + 1); // Allocate enough space for this primitive, plus the restart index
std::vector<u16> Indices(pPrim->Vertices.size()); u16 VBOStartOffset = (u16) mVBO.Size();
for (u32 iVert = 0; iVert < pPrim->Vertices.size(); iVert++) mVBO.Reserve((u16) pSurf->VertexCount);
Indices[iVert] = mVBO.AddIfUnique(pPrim->Vertices[iVert], VBOStartOffset);
// then add the indices to the IBO. We convert some primitives to strips to minimize draw calls. for (u32 iPrim = 0; iPrim < pSurf->Primitives.size(); iPrim++)
switch (pPrim->Type) { {
case eGX_Triangles: SSurface::SPrimitive *pPrim = &pSurf->Primitives[iPrim];
pIBO->TrianglesToStrips(Indices.data(), Indices.size()); CIndexBuffer *pIBO = InternalGetIBO(iSurf, pPrim->Type);
break; pIBO->Reserve(pPrim->Vertices.size() + 1); // Allocate enough space for this primitive, plus the restart index
case eGX_TriangleFan:
pIBO->FansToStrips(Indices.data(), Indices.size()); std::vector<u16> Indices(pPrim->Vertices.size());
break; for (u32 iVert = 0; iVert < pPrim->Vertices.size(); iVert++)
case eGX_Quads: Indices[iVert] = mVBO.AddIfUnique(pPrim->Vertices[iVert], VBOStartOffset);
pIBO->QuadsToStrips(Indices.data(), Indices.size());
break; // then add the indices to the IBO. We convert some primitives to strips to minimize draw calls.
default: switch (pPrim->Type) {
pIBO->AddIndices(Indices.data(), Indices.size()); case eGX_Triangles:
pIBO->AddIndex(0xFFFF); // primitive restart pIBO->TrianglesToStrips(Indices.data(), Indices.size());
break; break;
case eGX_TriangleFan:
pIBO->FansToStrips(Indices.data(), Indices.size());
break;
case eGX_Quads:
pIBO->QuadsToStrips(Indices.data(), Indices.size());
break;
default:
pIBO->AddIndices(Indices.data(), Indices.size());
pIBO->AddIndex(0xFFFF); // primitive restart
break;
}
} }
}
}
mBuffered = true; for (u32 iIBO = 0; iIBO < mSurfaceIndexBuffers[iSurf].size(); iIBO++)
mSurfaceIndexBuffers[iSurf][iIBO].Buffer();
}
mBuffered = true;
}
} }
void CModel::GenerateMaterialShaders() void CModel::GenerateMaterialShaders()
@ -92,7 +98,7 @@ void CModel::GenerateMaterialShaders()
void CModel::ClearGLBuffer() void CModel::ClearGLBuffer()
{ {
mVBO.Clear(); mVBO.Clear();
mSubmeshIndexBuffers.clear(); mSurfaceIndexBuffers.clear();
mBuffered = false; mBuffered = false;
} }
@ -127,9 +133,9 @@ void CModel::DrawSurface(FRenderOptions Options, u32 Surface, u32 MatSet)
mVBO.Bind(); mVBO.Bind();
glLineWidth(1.f); glLineWidth(1.f);
for (u32 iIBO = 0; iIBO < mSubmeshIndexBuffers[Surface].size(); iIBO++) for (u32 iIBO = 0; iIBO < mSurfaceIndexBuffers[Surface].size(); iIBO++)
{ {
CIndexBuffer *pIBO = &mSubmeshIndexBuffers[Surface][iIBO]; CIndexBuffer *pIBO = &mSurfaceIndexBuffers[Surface][iIBO];
pIBO->DrawElements(); pIBO->DrawElements();
} }
@ -209,7 +215,7 @@ bool CModel::IsSurfaceTransparent(u32 Surface, u32 MatSet)
CIndexBuffer* CModel::InternalGetIBO(u32 Surface, EGXPrimitiveType Primitive) CIndexBuffer* CModel::InternalGetIBO(u32 Surface, EGXPrimitiveType Primitive)
{ {
std::vector<CIndexBuffer> *pIBOs = &mSubmeshIndexBuffers[Surface]; std::vector<CIndexBuffer> *pIBOs = &mSurfaceIndexBuffers[Surface];
GLenum Type = GXPrimToGLPrim(Primitive); GLenum Type = GXPrimToGLPrim(Primitive);
for (u32 iIBO = 0; iIBO < pIBOs->size(); iIBO++) for (u32 iIBO = 0; iIBO < pIBOs->size(); iIBO++)

View File

@ -14,7 +14,7 @@ class CModel : public CBasicModel
friend class CModelCooker; friend class CModelCooker;
std::vector<CMaterialSet*> mMaterialSets; std::vector<CMaterialSet*> mMaterialSets;
std::vector<std::vector<CIndexBuffer>> mSubmeshIndexBuffers; std::vector<std::vector<CIndexBuffer>> mSurfaceIndexBuffers;
bool mHasOwnMaterials; bool mHasOwnMaterials;
public: public:

View File

@ -34,59 +34,62 @@ void CStaticModel::AddSurface(SSurface *pSurface)
void CStaticModel::BufferGL() void CStaticModel::BufferGL()
{ {
mVBO.Clear(); if (!mBuffered)
mIBOs.clear();
for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
{ {
SSurface *pSurf = mSurfaces[iSurf]; mVBO.Clear();
mIBOs.clear();
u16 VBOStartOffset = (u16) mVBO.Size(); for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
mVBO.Reserve((u16) pSurf->VertexCount);
for (u32 iPrim = 0; iPrim < pSurf->Primitives.size(); iPrim++)
{ {
SSurface::SPrimitive *pPrim = &pSurf->Primitives[iPrim]; SSurface *pSurf = mSurfaces[iSurf];
CIndexBuffer *pIBO = InternalGetIBO(pPrim->Type);
pIBO->Reserve(pPrim->Vertices.size() + 1); // Allocate enough space for this primitive, plus the restart index
// Next step: add new vertices to the VBO and create a small index buffer for the current primitive u16 VBOStartOffset = (u16) mVBO.Size();
std::vector<u16> Indices(pPrim->Vertices.size()); mVBO.Reserve((u16) pSurf->VertexCount);
for (u32 iVert = 0; iVert < pPrim->Vertices.size(); iVert++)
Indices[iVert] = mVBO.AddIfUnique(pPrim->Vertices[iVert], VBOStartOffset);
// then add the indices to the IBO. We convert some primitives to strips to minimize draw calls. for (u32 iPrim = 0; iPrim < pSurf->Primitives.size(); iPrim++)
switch (pPrim->Type) { {
case eGX_Triangles: SSurface::SPrimitive *pPrim = &pSurf->Primitives[iPrim];
pIBO->TrianglesToStrips(Indices.data(), Indices.size()); CIndexBuffer *pIBO = InternalGetIBO(pPrim->Type);
break; pIBO->Reserve(pPrim->Vertices.size() + 1); // Allocate enough space for this primitive, plus the restart index
case eGX_TriangleFan:
pIBO->FansToStrips(Indices.data(), Indices.size()); // Next step: add new vertices to the VBO and create a small index buffer for the current primitive
break; std::vector<u16> Indices(pPrim->Vertices.size());
case eGX_Quads: for (u32 iVert = 0; iVert < pPrim->Vertices.size(); iVert++)
pIBO->QuadsToStrips(Indices.data(), Indices.size()); Indices[iVert] = mVBO.AddIfUnique(pPrim->Vertices[iVert], VBOStartOffset);
break;
default: // then add the indices to the IBO. We convert some primitives to strips to minimize draw calls.
pIBO->AddIndices(Indices.data(), Indices.size()); switch (pPrim->Type) {
pIBO->AddIndex(0xFFFF); // primitive restart case eGX_Triangles:
break; pIBO->TrianglesToStrips(Indices.data(), Indices.size());
break;
case eGX_TriangleFan:
pIBO->FansToStrips(Indices.data(), Indices.size());
break;
case eGX_Quads:
pIBO->QuadsToStrips(Indices.data(), Indices.size());
break;
default:
pIBO->AddIndices(Indices.data(), Indices.size());
pIBO->AddIndex(0xFFFF); // primitive restart
break;
}
} }
// Make sure the number of submesh offset vectors matches the number of IBOs, then add the offsets
while (mIBOs.size() > mSubmeshEndOffsets.size())
mSubmeshEndOffsets.emplace_back(std::vector<u32>(mSurfaces.size()));
for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++)
mSubmeshEndOffsets[iIBO][iSurf] = mIBOs[iIBO].GetSize();
} }
// Make sure the number of submesh offset vectors matches the number of IBOs, then add the offsets mVBO.Buffer();
while (mIBOs.size() > mSubmeshEndOffsets.size())
mSubmeshEndOffsets.emplace_back(std::vector<u32>(mSurfaces.size()));
for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++) for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++)
mSubmeshEndOffsets[iIBO][iSurf] = mIBOs[iIBO].GetSize(); mIBOs[iIBO].Buffer();
mBuffered = true;
} }
mVBO.Buffer();
for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++)
mIBOs[iIBO].Buffer();
mBuffered = true;
} }
void CStaticModel::GenerateMaterialShaders() void CStaticModel::GenerateMaterialShaders()

View File

@ -33,7 +33,7 @@ CModelNode* CScene::CreateModelNode(CModel *pModel)
{ {
if (pModel == nullptr) return nullptr; if (pModel == nullptr) return nullptr;
CModelNode *pNode = new CModelNode(this, mpSceneRootNode, pModel); CModelNode *pNode = new CModelNode(this, mpAreaRootNode, pModel);
mNodes[eModelNode].push_back(pNode); mNodes[eModelNode].push_back(pNode);
mNumNodes++; mNumNodes++;
return pNode; return pNode;
@ -82,10 +82,7 @@ CLightNode* CScene::CreateLightNode(CLight *pLight)
void CScene::SetActiveArea(CGameArea *pArea) void CScene::SetActiveArea(CGameArea *pArea)
{ {
// Clear existing area // Clear existing area
delete mpAreaRootNode; ClearScene();
mNodes.clear();
mAreaAttributesObjects.clear();
mScriptNodeMap.clear();
// Create nodes for new area // Create nodes for new area
mpArea = pArea; mpArea = pArea;
@ -203,10 +200,11 @@ void CScene::ClearScene()
} }
mNodes.clear(); mNodes.clear();
mAreaAttributesObjects.clear();
mScriptNodeMap.clear();
mNumNodes = 0; mNumNodes = 0;
mpArea = nullptr; mpArea = nullptr;
mpWorld = nullptr;
} }
void CScene::AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) void CScene::AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)