vk: studio: clear submodule cache at appropriate times

Add render refcount to submodels to diagnose when it can't properly clear things due to them being used somewhere still.

Also add `speeds.submodels_cache_{dynamic,static}` counters to show how many submodels render models have been allocated.
This commit is contained in:
Ivan 'provod' Avdeev 2023-08-28 11:58:38 -04:00 committed by Ivan Avdeev
parent 03fc537d54
commit 45a141aa36
4 changed files with 38 additions and 22 deletions

View File

@ -22,6 +22,7 @@
#include "vk_sprite.h"
#include "vk_beams.h"
#include "vk_combuf.h"
#include "vk_entity_data.h"
// FIXME move this rt-specific stuff out
#include "vk_light.h"
@ -810,6 +811,8 @@ qboolean R_VkInit( void )
void R_VkShutdown( void ) {
XVK_CHECK(vkDeviceWaitIdle(vk_core.device));
VK_EntityDataClear();
R_SpriteShutdown();
if (vk_core.rtx)

View File

@ -19,6 +19,7 @@
#include "camera.h"
#include "vk_mapents.h"
#include "profiler.h"
#include "vk_entity_data.h"
#include "com_strings.h"
#include "ref_params.h"
@ -85,6 +86,7 @@ static void loadLights( const model_t *const map ) {
// Clears all old map data
static void mapLoadBegin( const model_t *const map ) {
VK_EntityDataClear();
R_StudioCacheClear();
R_GeometryBuffer_MapClear();

View File

@ -6,16 +6,6 @@
#define MODULE_NAME "studio"
// FIXME:
// - [ ] (CRASH) Cache coherence: entities are reused between frames for different studio models. Catch and handle it.
// If it was literally reused between sequential frames, then we're screwed, because we can't delete the previous one, as it might be still in use on GPU. Needs refcounts infrastructure.
// Currently we just push render_submodels being released back into cache. And we don't destroy them ever.
// This needs to change.
// TODO add clearing cache function. Also make sure that it is called on shutdown.
// TODO Potential optimization: (MIGHT STILL NEED THIS FOR DENOISER MOVE VECTORS)
// Keep last generated verts. Compare new verts with previous ones. If they are the same, do not rebuild the BLAS.
typedef struct {
const studiohdr_t *studio_header_key;
r_studio_model_info_t info;
@ -25,6 +15,9 @@ static struct {
#define MAX_STUDIO_MODELS 256
r_studio_model_info_entry_t models[MAX_STUDIO_MODELS];
int models_count;
int submodels_cached_dynamic;
int submodels_cached_static;
} g_studio_cache;
void studioRenderSubmodelDestroy( r_studio_submodel_render_t *submodel ) {
@ -35,6 +28,9 @@ void studioRenderSubmodelDestroy( r_studio_submodel_render_t *submodel ) {
}
static void studioSubmodelInfoDestroy(r_studio_submodel_info_t *subinfo) {
// Not zero means that something still holds a cached render submodel instance somewhere
ASSERT(subinfo->render_refcount == 0);
while (subinfo->cached_head) {
r_studio_submodel_render_t *render = subinfo->cached_head;
subinfo->cached_head = subinfo->cached_head->_.next;
@ -53,6 +49,8 @@ void R_StudioCacheClear( void ) {
Mem_Free(info->submodels);
}
g_studio_cache.models_count = 0;
g_studio_cache.submodels_cached_dynamic = g_studio_cache.submodels_cached_static = 0;
}
static struct {
@ -219,7 +217,8 @@ r_studio_model_info_t *getStudioModelInfo(model_t *model) {
}
void VK_StudioModelInit(void) {
// FIXME R_SPEEDS_METRIC(g_studio_cache.entries_count, "cached_submodels", kSpeedsMetricCount);
R_SPEEDS_METRIC(g_studio_cache.submodels_cached_static, "submodels_cached_static", kSpeedsMetricCount);
R_SPEEDS_METRIC(g_studio_cache.submodels_cached_dynamic, "submodels_cached_dynamic", kSpeedsMetricCount);
}
r_studio_submodel_render_t *studioSubmodelRenderModelAcquire(r_studio_submodel_info_t *subinfo) {
@ -230,15 +229,21 @@ r_studio_submodel_render_t *studioSubmodelRenderModelAcquire(r_studio_submodel_i
subinfo->cached_head = render->_.next;
render->_.next = NULL;
}
subinfo->render_refcount++;
return render;
}
render = Mem_Calloc(vk_core.pool, sizeof(*render));
render->_.info = subinfo;
if (!subinfo->is_dynamic)
if (!subinfo->is_dynamic) {
subinfo->cached_head = render;
++g_studio_cache.submodels_cached_static;
} else {
++g_studio_cache.submodels_cached_dynamic;
}
subinfo->render_refcount++;
return render;
}
@ -246,6 +251,9 @@ void studioSubmodelRenderModelRelease(r_studio_submodel_render_t *render_submode
if (!render_submodel)
return;
ASSERT(render_submodel->_.info->render_refcount > 0);
render_submodel->_.info->render_refcount--;
if (!render_submodel->_.info->is_dynamic)
return;

View File

@ -4,6 +4,11 @@
#include "vk_geometry.h"
struct r_studio_submodel_info_s;
// Submodel render data that is enough to render given submodel
// Included render model (that also incapsulates BLAS)
// This can be static (built once), or dynamic (updated frequently)
// Lives in per-model-info submodel cache
typedef struct r_studio_submodel_render_s {
vk_render_model_t model;
r_geometry_range_t geometry_range;
@ -21,6 +26,7 @@ typedef struct r_studio_submodel_render_s {
} _;
} r_studio_submodel_render_t;
// Submodel metadata and render-model cache
typedef struct r_studio_submodel_info_s {
const mstudiomodel_t *submodel_key;
qboolean is_dynamic;
@ -28,8 +34,12 @@ typedef struct r_studio_submodel_info_s {
// TODO int verts_count; for prev_verts
r_studio_submodel_render_t *cached_head;
// Mostly for debug: how many cached render models were acquired and not given back
int render_refcount;
} r_studio_submodel_info_t;
// Submodel cache functions, used in vk_studio.c
r_studio_submodel_render_t *studioSubmodelRenderModelAcquire(r_studio_submodel_info_t *info);
void studioSubmodelRenderModelRelease(r_studio_submodel_render_t *render_submodel);
@ -38,7 +48,7 @@ typedef struct {
r_studio_submodel_info_t *submodels;
} r_studio_model_info_t;
void VK_StudioModelInit(void);
r_studio_model_info_t *getStudioModelInfo(model_t *model);
// Entity model cache/pool
typedef struct {
@ -52,12 +62,5 @@ typedef struct {
r_studio_submodel_render_t **bodyparts;
} r_studio_entity_model_t;
//r_studio_entity_model_t *studioEntityModelGet(const cl_entity_t *ent);
// TOOD manual cleanup function? free unused?
//void studioEntityModelClear(void);
void studioRenderSubmodelDestroy( r_studio_submodel_render_t *submodel );
r_studio_model_info_t *getStudioModelInfo(model_t *model);
void VK_StudioModelInit(void);
//void VK_StudioModelShutdown(void);