| … | … | @@ -7864,11 +7864,30 @@ void RenderingDevice::_free_internal(RID p_id) { |
| 7864 | 7864 | trace_count++; |
| 7865 | 7865 | trace_suffix = "\n" + backtrace_dump() + " [trace " + itos(trace_count) + "/20]"; |
| 7866 | 7866 | } |
| 7867 | |
| 7868 | // This fires per double-freed RID, and something upstream can produce |
| 7869 | // hundreds per frame. ERR_PRINT is not cheap -- string building plus |
| 7870 | // synchronous stderr -- so unbounded spam becomes a framerate problem in |
| 7871 | // its own right, on top of whatever bug is causing the frees. Print the |
| 7872 | // first PRINT_LIMIT in full (the backtraces are the diagnostic), then |
| 7873 | // report a running total periodically instead of every occurrence. |
| 7874 | constexpr int PRINT_LIMIT = 64; |
| 7875 | static int invalid_free_count = 0; |
| 7876 | invalid_free_count++; |
| 7877 | |
| 7878 | if (invalid_free_count <= PRINT_LIMIT) { |
| 7867 | 7879 | #ifdef DEV_ENABLED |
| 7868 | | ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name + trace_suffix); |
| 7880 | ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name + trace_suffix); |
| 7869 | 7881 | #else |
| 7870 | | ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + trace_suffix); |
| 7882 | ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + trace_suffix); |
| 7871 | 7883 | #endif |
| 7884 | if (invalid_free_count == PRINT_LIMIT) { |
| 7885 | ERR_PRINT("Attempted to free invalid ID: reached " + itos(PRINT_LIMIT) + |
| 7886 | " reports; further occurrences are counted, not printed."); |
| 7887 | } |
| 7888 | } else if ((invalid_free_count % 1000) == 0) { |
| 7889 | ERR_PRINT("Attempted to free invalid ID: " + itos(invalid_free_count) + " total occurrences so far."); |
| 7890 | } |
| 7872 | 7891 | } |
| 7873 | 7892 | |
| 7874 | 7893 | frames_pending_resources_for_processing = uint32_t(frames.size()); |