diff --git a/ref/vk/vk_core.c b/ref/vk/vk_core.c index 8d216d7e..c018d111 100644 --- a/ref/vk/vk_core.c +++ b/ref/vk/vk_core.c @@ -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) diff --git a/ref/vk/vk_scene.c b/ref/vk/vk_scene.c index d95c09fb..f2e6ba93 100644 --- a/ref/vk/vk_scene.c +++ b/ref/vk/vk_scene.c @@ -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(); diff --git a/ref/vk/vk_studio_model.c b/ref/vk/vk_studio_model.c index 6fe171c4..a9fa9e4f 100644 --- a/ref/vk/vk_studio_model.c +++ b/ref/vk/vk_studio_model.c @@ -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; diff --git a/ref/vk/vk_studio_model.h b/ref/vk/vk_studio_model.h index 8ea9ec5e..ff1b368f 100644 --- a/ref/vk/vk_studio_model.h +++ b/ref/vk/vk_studio_model.h @@ -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);