From a056e027b02076083f7f36e4f787ad4476c8fda6 Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 25 Apr 2007 14:47:02 +0000 Subject: [PATCH] added tracking of memory usage of VBO/EBO buffers added gl_vbostats command to list VBO/EBO buffers added total VBO/EBO usage information in memstats git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7192 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_backend.c | 92 +++++++++++++++++++++++++++++++++++++++++--------- gl_backend.h | 13 ++++--- model_shared.c | 16 ++++----- zone.c | 1 + 4 files changed, 93 insertions(+), 29 deletions(-) diff --git a/gl_backend.c b/gl_backend.c index 93d23b77..9db25435 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -144,6 +144,22 @@ void GL_Backend_FreeArrays(void) { } +void GL_VBOStats_f(void) +{ + GL_Mesh_ListVBOs(true); +} + +typedef struct gl_bufferobjectinfo_s +{ + int target; + int object; + size_t size; + char name[MAX_QPATH]; +} +gl_bufferobjectinfo_t; + +memexpandablearray_t gl_bufferobjectinfoarray; + static void gl_backend_start(void) { Con_Print("OpenGL Backend starting...\n"); @@ -180,6 +196,8 @@ static void gl_backend_start(void) GL_Backend_AllocArrays(); + Mem_ExpandableArray_NewArray(&gl_bufferobjectinfoarray, r_main_mempool, sizeof(gl_bufferobjectinfo_t), 128); + Con_Printf("OpenGL backend started.\n"); CHECKGLERROR @@ -196,6 +214,8 @@ static void gl_backend_shutdown(void) Con_Print("OpenGL Backend shutting down\n"); + Mem_ExpandableArray_FreeArray(&gl_bufferobjectinfoarray); + GL_Backend_FreeArrays(); } @@ -241,6 +261,8 @@ void gl_backend_init(void) Cvar_RegisterVariable(&gl_mesh_testarrayelement); Cvar_RegisterVariable(&gl_mesh_testmanualfeeding); + Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them\n"); + R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap); } @@ -1096,36 +1118,74 @@ void R_Mesh_Finish(void) qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR } -int R_Mesh_CreateStaticEBO(void *data, size_t size) +int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name) { + gl_bufferobjectinfo_t *info; GLuint bufferobject; + if (!gl_vbo.integer) return 0; + qglGenBuffersARB(1, &bufferobject); - GL_BindEBO(bufferobject); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB); + switch(target) + { + case GL_ELEMENT_ARRAY_BUFFER_ARB: GL_BindEBO(bufferobject);break; + case GL_ARRAY_BUFFER_ARB: GL_BindVBO(bufferobject);break; + default: Sys_Error("R_Mesh_CreateStaticBufferObject: unknown target type %i\n", target);return 0; + } + qglBufferDataARB(target, size, data, GL_STATIC_DRAW_ARB); + + info = Mem_ExpandableArray_AllocRecord(&gl_bufferobjectinfoarray); + memset(info, 0, sizeof(*info)); + info->target = target; + info->object = bufferobject; + info->size = size; + strlcpy(info->name, name, sizeof(info->name)); + return (int)bufferobject; } -void R_Mesh_DestroyEBO(int bufferobject) +void R_Mesh_DestroyBufferObject(int bufferobject) { + int i, endindex; + gl_bufferobjectinfo_t *info; + qglDeleteBuffersARB(1, (GLuint *)&bufferobject); -} -int R_Mesh_CreateStaticVBO(void *data, size_t size) -{ - GLuint bufferobject; - if (!gl_vbo.integer) - return 0; - qglGenBuffersARB(1, &bufferobject); - GL_BindVBO(bufferobject); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB); - return (int)bufferobject; + endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray); + for (i = 0;i < endindex;i++) + { + info = Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i); + if (!info) + continue; + if (info->object == bufferobject) + { + Mem_ExpandableArray_FreeRecord(&gl_bufferobjectinfoarray, (void *)info); + break; + } + } } -void R_Mesh_DestroyVBO(int bufferobject) +void GL_Mesh_ListVBOs(qboolean printeach) { - qglDeleteBuffersARB(1, (GLuint *)&bufferobject); + int i, endindex; + size_t ebocount = 0, ebomemory = 0; + size_t vbocount = 0, vbomemory = 0; + gl_bufferobjectinfo_t *info; + endindex = Mem_ExpandableArray_IndexRange(&gl_bufferobjectinfoarray); + for (i = 0;i < endindex;i++) + { + info = Mem_ExpandableArray_RecordAtIndex(&gl_bufferobjectinfoarray, i); + if (!info) + continue; + switch(info->target) + { + case GL_ELEMENT_ARRAY_BUFFER_ARB: ebocount++;ebomemory += info->size;if (printeach) Con_Printf("EBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break; + case GL_ARRAY_BUFFER_ARB: vbocount++;vbomemory += info->size;if (printeach) Con_Printf("VBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break; + default: Con_Printf("gl_vbostats: unknown target type %i\n", info->target);break; + } + } + Con_Printf("vertex buffers: %i element buffers totalling %i bytes (%.3f MB), %i vertex buffers totalling %i bytes (%.3f MB), combined %i bytes (%.3fMB)\n", (int)ebocount, (int)ebomemory, ebomemory / 1048576.0, (int)vbocount, (int)vbomemory, vbomemory / 1048576.0, (int)(ebomemory + vbomemory), (ebomemory + vbomemory) / 1048576.0); } void R_Mesh_Matrix(const matrix4x4_t *matrix) diff --git a/gl_backend.h b/gl_backend.h index a51c6da7..088cdb32 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -77,11 +77,14 @@ void R_Mesh_Finish(void); int R_Mesh_CreateStaticEBO(void *data, size_t size); // frees an element array buffer object void R_Mesh_DestroyEBO(int bufferobject); -// allocates a static vertex array buffer object -// (storing vertex data in video memory) -int R_Mesh_CreateStaticVBO(void *data, size_t size); -// frees a vertex array buffer object -void R_Mesh_DestroyVBO(int bufferobject); +// allocates a static vertex/element array buffer object +// (storing vertex or element data in video memory) +// target is GL_ELEMENT_ARRAY_BUFFER_ARB (triangle elements) +// or GL_ARRAY_BUFFER_ARB (vertex data) +int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name); +// frees a vertex/element array buffer object +void R_Mesh_DestroyBufferObject(int bufferobject); +void GL_Mesh_ListVBOs(qboolean printeach); // sets up the requested vertex transform matrix void R_Mesh_Matrix(const matrix4x4_t *matrix); diff --git a/model_shared.c b/model_shared.c index 79298781..12e32847 100644 --- a/model_shared.c +++ b/model_shared.c @@ -143,9 +143,9 @@ void Mod_UnloadModel (model_t *mod) isworldmodel = mod->isworldmodel; used = mod->used; if (mod->surfmesh.ebo) - R_Mesh_DestroyEBO(mod->surfmesh.ebo); + R_Mesh_DestroyBufferObject(mod->surfmesh.ebo); if (mod->surfmesh.vbo) - R_Mesh_DestroyVBO(mod->surfmesh.vbo); + R_Mesh_DestroyBufferObject(mod->surfmesh.vbo); // free textures/memory attached to the model R_FreeTexturePool(&mod->texturepool); Mem_FreePool(&mod->mempool); @@ -937,7 +937,7 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh) // element buffer is easy because it's just one array if (mesh->numtriangles) - mesh->ebo = R_Mesh_CreateStaticEBO(mesh->element3i, mesh->numtriangles * sizeof(int[3])); + mesh->ebo = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh->element3i, mesh->numtriangles * sizeof(int[3]), "shadowmesh"); // vertex buffer is several arrays and we put them in the same buffer // @@ -960,7 +960,7 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh) if (mesh->tvector3f ) memcpy(mem + mesh->vbooffset_tvector3f , mesh->tvector3f , mesh->numverts * sizeof(float[3])); if (mesh->normal3f ) memcpy(mem + mesh->vbooffset_normal3f , mesh->normal3f , mesh->numverts * sizeof(float[3])); if (mesh->texcoord2f ) memcpy(mem + mesh->vbooffset_texcoord2f , mesh->texcoord2f , mesh->numverts * sizeof(float[2])); - mesh->vbo = R_Mesh_CreateStaticVBO(mem, size); + mesh->vbo = R_Mesh_CreateStaticBufferObject(GL_ARRAY_BUFFER_ARB, mem, size, "shadowmesh"); Mem_Free(mem); } } @@ -1040,9 +1040,9 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh) for (;mesh;mesh = nextmesh) { if (mesh->ebo) - R_Mesh_DestroyEBO(mesh->ebo); + R_Mesh_DestroyBufferObject(mesh->ebo); if (mesh->vbo) - R_Mesh_DestroyVBO(mesh->vbo); + R_Mesh_DestroyBufferObject(mesh->vbo); nextmesh = mesh->next; Mem_Free(mesh); } @@ -1323,7 +1323,7 @@ static void Mod_BuildVBOs(void) // element buffer is easy because it's just one array if (loadmodel->surfmesh.num_triangles) - loadmodel->surfmesh.ebo = R_Mesh_CreateStaticEBO(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3])); + loadmodel->surfmesh.ebo = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name); // vertex buffer is several arrays and we put them in the same buffer // @@ -1350,7 +1350,7 @@ static void Mod_BuildVBOs(void) if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2])); if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2])); if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4])); - loadmodel->surfmesh.vbo = R_Mesh_CreateStaticVBO(mem, size); + loadmodel->surfmesh.vbo = R_Mesh_CreateStaticBufferObject(GL_ARRAY_BUFFER_ARB, mem, size, loadmodel->name); Mem_Free(mem); } } diff --git a/zone.c b/zone.c index 829f25cb..32655d9a 100644 --- a/zone.c +++ b/zone.c @@ -553,6 +553,7 @@ void MemStats_f(void) { Mem_CheckSentinelsGlobal(); R_TextureStats_Print(false, false, true); + GL_Mesh_ListVBOs(false); Mem_PrintStats(); } -- 2.39.2