| … | … | @@ -7733,6 +7733,46 @@ void RenderingDevice::_free_internal(RID p_id) { |
| 7733 | 7733 | // record which IDs were genuinely freed. That history is what lets a later |
| 7734 | 7734 | // invalid free be reported as a DOUBLE free rather than just "invalid". |
| 7735 | 7735 | bool dbg_was_invalid = false; |
| 7736 | |
| 7737 | // Which owner held this ID, captured BEFORE the chain below frees it. Knowing |
| 7738 | // a double-freed ID was an acceleration structure rather than a uniform set is |
| 7739 | // the difference between one suspect cache and seventeen. |
| 7740 | const char *dbg_owner_kind = nullptr; |
| 7741 | if (texture_owner.owns(p_id)) { |
| 7742 | dbg_owner_kind = "texture"; |
| 7743 | } else if (framebuffer_owner.owns(p_id)) { |
| 7744 | dbg_owner_kind = "framebuffer"; |
| 7745 | } else if (sampler_owner.owns(p_id)) { |
| 7746 | dbg_owner_kind = "sampler"; |
| 7747 | } else if (vertex_buffer_owner.owns(p_id)) { |
| 7748 | dbg_owner_kind = "vertex_buffer"; |
| 7749 | } else if (vertex_array_owner.owns(p_id)) { |
| 7750 | dbg_owner_kind = "vertex_array"; |
| 7751 | } else if (index_buffer_owner.owns(p_id)) { |
| 7752 | dbg_owner_kind = "index_buffer"; |
| 7753 | } else if (index_array_owner.owns(p_id)) { |
| 7754 | dbg_owner_kind = "index_array"; |
| 7755 | } else if (shader_owner.owns(p_id)) { |
| 7756 | dbg_owner_kind = "shader"; |
| 7757 | } else if (uniform_buffer_owner.owns(p_id)) { |
| 7758 | dbg_owner_kind = "uniform_buffer"; |
| 7759 | } else if (texture_buffer_owner.owns(p_id)) { |
| 7760 | dbg_owner_kind = "texture_buffer"; |
| 7761 | } else if (storage_buffer_owner.owns(p_id)) { |
| 7762 | dbg_owner_kind = "storage_buffer"; |
| 7763 | } else if (uniform_set_owner.owns(p_id)) { |
| 7764 | dbg_owner_kind = "uniform_set"; |
| 7765 | } else if (render_pipeline_owner.owns(p_id)) { |
| 7766 | dbg_owner_kind = "render_pipeline"; |
| 7767 | } else if (compute_pipeline_owner.owns(p_id)) { |
| 7768 | dbg_owner_kind = "compute_pipeline"; |
| 7769 | } else if (acceleration_structure_owner.owns(p_id)) { |
| 7770 | dbg_owner_kind = "acceleration_structure"; |
| 7771 | } else if (raytracing_pipeline_owner.owns(p_id)) { |
| 7772 | dbg_owner_kind = "raytracing_pipeline"; |
| 7773 | } else if (hit_sbt_owner.owns(p_id)) { |
| 7774 | dbg_owner_kind = "hit_sbt"; |
| 7775 | } |
| 7736 | 7776 | #endif |
| 7737 | 7777 | #ifdef DEV_ENABLED |
| 7738 | 7778 | String resource_name; |
| … | … | @@ -7894,14 +7934,23 @@ void RenderingDevice::_free_internal(RID p_id) { |
| 7894 | 7934 | // "never valid" -> it was never a live RID here: uninitialised or |
| 7895 | 7935 | // corrupted memory, or an ID from another RD instance. |
| 7896 | 7936 | // |
| 7897 | | // The RID is also decoded: RID_Alloc packs (index << 32) | validator, so a |
| 7898 | | // recurring index with a changing validator is slot reuse -- the signature |
| 7899 | | // of stale handles surviving a free/realloc cycle. |
| 7937 | // The RID is also decoded. RID_Alloc packs (validator << 32) | index -- |
| 7938 | // see rid_owner.h:157-158 (`id = validator; id <<= 32;`) and :382 |
| 7939 | // (`_make_from_id((validator << 32) | i)`). The validator is a process-wide |
| 7940 | // monotonic counter (`_gen_id()` -> `base_id.increment()`), so it reads as |
| 7941 | // allocation birth-order; the index is the slot in this owner. A recurring |
| 7942 | // index with a rising validator is slot reuse -- the signature of a stale |
| 7943 | // handle surviving a free/realloc cycle. |
| 7900 | 7944 | String dbg_decoded; |
| 7901 | 7945 | #ifdef DEBUG_ENABLED |
| 7902 | | String dbg_kind = _dbg_freed_ids.has(p_id.get_id()) ? "DOUBLE FREE (freed before)" : "never valid"; |
| 7903 | | dbg_decoded = " [index=" + itos(p_id.get_id() >> 32) + |
| 7904 | | " validator=" + itos(p_id.get_id() & 0xFFFFFFFF) + " " + dbg_kind + "]"; |
| 7946 | String dbg_kind = "never valid"; |
| 7947 | if (_dbg_freed_ids.has(p_id.get_id())) { |
| 7948 | dbg_kind = "DOUBLE FREE (freed before, was "; |
| 7949 | dbg_kind += _dbg_freed_ids[p_id.get_id()]; |
| 7950 | dbg_kind += ")"; |
| 7951 | } |
| 7952 | dbg_decoded = " [validator=" + itos(p_id.get_id() >> 32) + |
| 7953 | " index=" + itos(p_id.get_id() & 0xFFFFFFFF) + " " + dbg_kind + "]"; |
| 7905 | 7954 | #endif |
| 7906 | 7955 | |
| 7907 | 7956 | if (invalid_free_count <= PRINT_LIMIT) { |
| … | … | @@ -7921,7 +7970,7 @@ void RenderingDevice::_free_internal(RID p_id) { |
| 7921 | 7970 | |
| 7922 | 7971 | #ifdef DEBUG_ENABLED |
| 7923 | 7972 | if (!dbg_was_invalid) { |
| 7924 | | _dbg_freed_ids.insert(p_id.get_id()); |
| 7973 | _dbg_freed_ids.insert(p_id.get_id(), dbg_owner_kind ? dbg_owner_kind : "unknown"); |
| 7925 | 7974 | } |
| 7926 | 7975 | #endif |
| 7927 | 7976 | |