Fixes to avoid needless re-buffering in PostLoad + fix for a crash/memory leak when changing areas
This commit is contained in:
parent
7bd97f0fce
commit
3296948bea
|
@ -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++)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue