| … | … | @@ -254,6 +254,21 @@ uint64_t RenderRaytracing::mat_ubo_pool_get_address(uint32_t p_slot) const { |
| 254 | 254 | // Cache management |
| 255 | 255 | // --------------------------------------------------------------------------- |
| 256 | 256 | |
| 257 | // A cached BLAS can be reclaimed out from under us. blas_create registers the BLAS |
| 258 | // as a dependency of the vertex/index buffers it was built from |
| 259 | // (rendering_device.cpp:444), and _free_dependencies frees every dependent when the |
| 260 | // buffer goes, so a streaming mesh dropping its buffers takes the BLAS with it. The |
| 261 | // cache entry still holds the RID, and RID::is_valid() only tests for non-null -- it |
| 262 | // cannot see that the RD already reclaimed the slot -- so the next refresh frees it a |
| 263 | // second time. That is the "Attempted to free invalid ID ... was acceleration_structure" |
| 264 | // storm: hundreds per frame under dc-terrain streaming (hyper-games #11 §7.3). |
| 265 | static void rt_free_blas_if_owned(RID &r_blas) { |
| 266 | if (r_blas.is_valid() && RD::get_singleton()->acceleration_structure_is_valid(r_blas)) { |
| 267 | RD::get_singleton()->free_rid(r_blas); |
| 268 | } |
| 269 | r_blas = RID(); |
| 270 | } |
| 271 | |
| 257 | 272 | void RenderRaytracing::cleanup_caches() { |
| 258 | 273 | // Free all cached surface data. BLAS resources are NOT freed here because |
| 259 | 274 | // they are owned by the RD dependency chain. |
| … | … | @@ -274,9 +289,7 @@ void RenderRaytracing::cleanup_caches() { |
| 274 | 289 | for (KeyValue<uint64_t, RTDeformedCacheEntry> &kv : deformed_surface_cache) { |
| 275 | 290 | RTDeformedCacheEntry &e = kv.value; |
| 276 | 291 | if (e.ptr) { |
| 277 | | if (e.ptr->blas.is_valid()) { |
| 278 | | RD::get_singleton()->free_rid(e.ptr->blas); |
| 279 | | } |
| 292 | rt_free_blas_if_owned(e.ptr->blas); |
| 280 | 293 | memdelete(e.ptr); |
| 281 | 294 | e.ptr = nullptr; |
| 282 | 295 | } |
| … | … | @@ -396,9 +409,7 @@ void RenderRaytracing::prepare_frame() { |
| 396 | 409 | RTDeformedCacheEntry &e = kv.value; |
| 397 | 410 | if (e.last_used_frame != 0 && current_frame - e.last_used_frame > DEFORMED_CACHE_TTL_FRAMES) { |
| 398 | 411 | if (e.ptr) { |
| 399 | | if (e.ptr->blas.is_valid()) { |
| 400 | | RD::get_singleton()->free_rid(e.ptr->blas); |
| 401 | | } |
| 412 | rt_free_blas_if_owned(e.ptr->blas); |
| 402 | 413 | memdelete(e.ptr); |
| 403 | 414 | e.ptr = nullptr; |
| 404 | 415 | } |
| … | … | @@ -476,10 +487,9 @@ RTSurfaceData *RenderRaytracing::process_surface( |
| 476 | 487 | // Allocate or reuse entry |
| 477 | 488 | if (!entry->ptr) { |
| 478 | 489 | entry->ptr = memnew(RTSurfaceData); |
| 479 | | } else if (entry->ptr->blas.is_valid()) { |
| 480 | | // Free old BLAS before creating new one |
| 481 | | RD::get_singleton()->free_rid(entry->ptr->blas); |
| 482 | | entry->ptr->blas = RID(); |
| 490 | } else { |
| 491 | // Free the old BLAS before creating a new one -- if the RD still has it. |
| 492 | rt_free_blas_if_owned(entry->ptr->blas); |
| 483 | 493 | } |
| 484 | 494 | |
| 485 | 495 | RTSurfaceData *surf_data = entry->ptr; |
| … | … | @@ -567,9 +577,8 @@ RTSurfaceData *RenderRaytracing::process_deformed_surface( |
| 567 | 577 | |
| 568 | 578 | if (!entry.ptr) { |
| 569 | 579 | entry.ptr = memnew(RTSurfaceData); |
| 570 | | } else if (entry.ptr->blas.is_valid()) { |
| 571 | | RD::get_singleton()->free_rid(entry.ptr->blas); |
| 572 | | entry.ptr->blas = RID(); |
| 580 | } else { |
| 581 | rt_free_blas_if_owned(entry.ptr->blas); |
| 573 | 582 | entry.blas_built_once = false; |
| 574 | 583 | } |
| 575 | 584 | |
| … | … | @@ -1082,10 +1091,7 @@ void RenderRaytracing::update_procedural_blas(RTProceduralState *p_state, LocalV |
| 1082 | 1091 | |
| 1083 | 1092 | // Grow-only: only recreate the buffer when capacity is exceeded or count changed. |
| 1084 | 1093 | if (required_bytes > p_state->gpu_buffer_capacity || aabb_count != p_state->aabb_count) { |
| 1085 | | if (p_state->blas.is_valid()) { |
| 1086 | | RD::get_singleton()->free_rid(p_state->blas); |
| 1087 | | p_state->blas = RID(); |
| 1088 | | } |
| 1094 | rt_free_blas_if_owned(p_state->blas); |
| 1089 | 1095 | if (p_state->gpu_buffer.is_valid()) { |
| 1090 | 1096 | RD::get_singleton()->free_rid(p_state->gpu_buffer); |
| 1091 | 1097 | } |