rtx: cache and destroy model blases

Unfortunately Xash3D doesn't allow us to destroy models properly.
It doesn't call Mod_ProcessRenderData for all brush models (only map).
And by the time we get into R_Shutdown all models are already gone, so
we can't enumerate and destroy them properly.
This commit is contained in:
Ivan 'provod' Avdeev 2021-04-13 10:46:33 -07:00
parent 01e6a267d5
commit 28f2c06bdb
4 changed files with 33 additions and 2 deletions

View File

@ -1,10 +1,10 @@
## 2021-04-13
- [x] rtx: "toilet error": attempting to get AS device address crashes the driver
- [x] rtx: fix blas destruction on exit
# Next
- [ ] rtx: sometimes we get uninitialized models
- [ ] run under asan
- [ ] rtx: fix blas destruction on exit
- [ ] rtx: read rad file data
- [ ] rtx: hack: interpret textures with '~' or '{' as emissive
- [ ] rtx: emissive particles

View File

@ -356,6 +356,7 @@ qboolean VK_BrushModelLoad( model_t *mod )
void VK_BrushModelDestroy( model_t *mod ) {
vk_brush_model_t *bmodel = mod->cache.data;
ASSERT(mod->type == mod_brush);
if (!bmodel)
return;

View File

@ -18,7 +18,7 @@
#define PRINT_NOT_IMPLEMENTED_ARGS(msg, ...) do { \
static int called = 0; \
gEngine.Con_Printf( S_ERROR "VK NOT_IMPLEMENTED(x%d): %s" msg "\n", called, __FUNCTION__, __VA_ARGS__ ); \
gEngine.Con_Printf( S_ERROR "VK NOT_IMPLEMENTED(x%d): %s " msg "\n", called, __FUNCTION__, __VA_ARGS__ ); \
++called; \
} while(0)

View File

@ -111,6 +111,10 @@ static struct {
vk_image_t frames[2];
qboolean reload_pipeline;
// HACK: we don't have a way to properly destroy all models and their Vulkan objects on shutdown.
// This makes validation layers unhappy. Remember created objects here and destroy them manually.
VkAccelerationStructureKHR blases[MAX_ACCELS];
} g_rtx;
static VkDeviceAddress getBufferDeviceAddress(VkBuffer buffer) {
@ -900,6 +904,11 @@ void VK_RayShutdown( void )
if (g_rtx.tlas != VK_NULL_HANDLE)
vkDestroyAccelerationStructureKHR(vk_core.device, g_rtx.tlas, NULL);
for (int i = 0; i < ARRAYSIZE(g_rtx.blases); ++i) {
if (g_rtx.blases[i] != VK_NULL_HANDLE)
vkDestroyAccelerationStructureKHR(vk_core.device, g_rtx.blases[i], NULL);
}
destroyBuffer(&g_rtx.scratch_buffer);
destroyBuffer(&g_rtx.accels_buffer);
destroyBuffer(&g_rtx.tlas_geom_buffer);
@ -1030,7 +1039,18 @@ qboolean VK_RayModelInit( vk_ray_model_init_t args ) {
Mem_Free(geoms);
if (result) {
int blas_index;
g_rtx.map.num_kusochki += args.model->num_geometries;
for (blas_index = 0; blas_index < ARRAYSIZE(g_rtx.blases); ++blas_index) {
if (g_rtx.blases[blas_index] == VK_NULL_HANDLE) {
g_rtx.blases[blas_index] = args.model->rtx.blas;
break;
}
}
if (blas_index == ARRAYSIZE(g_rtx.blases))
gEngine.Con_Printf(S_WARN "Too many BLASes created :(\n");
}
gEngine.Con_Reportf("Model %s (%p) created blas %p\n", args.model->debug_name, args.model, args.model->rtx.blas);
@ -1041,6 +1061,16 @@ qboolean VK_RayModelInit( vk_ray_model_init_t args ) {
void VK_RayModelDestroy( struct vk_render_model_s *model ) {
ASSERT(vk_core.rtx);
if (model->rtx.blas != VK_NULL_HANDLE) {
int blas_index;
for (blas_index = 0; blas_index < ARRAYSIZE(g_rtx.blases); ++blas_index) {
if (g_rtx.blases[blas_index] == model->rtx.blas) {
g_rtx.blases[blas_index] = VK_NULL_HANDLE;
break;
}
}
if (blas_index == ARRAYSIZE(g_rtx.blases))
gEngine.Con_Printf(S_WARN "Model BLAS was missing\n");
vkDestroyAccelerationStructureKHR(vk_core.device, model->rtx.blas, NULL);
model->rtx.blas = VK_NULL_HANDLE;
}