From 266852c8b2f6f43433ee2bac6bca38ca3ad19bbc Mon Sep 17 00:00:00 2001 From: Harrand Date: Mon, 4 Nov 2024 21:30:21 +0000 Subject: [PATCH] [ren.quad] added ability to destroy a quad. this actually doesnt change the draw call at all, just makes the quad zero-sized and marks it as garbage to be re-used the next time the user adds a new quad. that way vram doesn't stay fragmented. --- include/tz/ren/quad.hpp | 1 + src/tz/ren/quad.cpp | 47 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/include/tz/ren/quad.hpp b/include/tz/ren/quad.hpp index a340aaed54..ed2a56b21e 100644 --- a/include/tz/ren/quad.hpp +++ b/include/tz/ren/quad.hpp @@ -48,6 +48,7 @@ namespace tz::ren tz::v3f colour = tz::v3f::filled(1.0f); }; std::expected quad_renderer_create_quad(quad_renderer_handle renh, quad_info info); + tz::error_code quad_renderer_destroy_quad(quad_renderer_handle renh, quad_handle quad); std::expected quad_renderer_add_texture(quad_renderer_handle renh, tz::gpu::resource_handle image); diff --git a/src/tz/ren/quad.cpp b/src/tz/ren/quad.cpp index 39c8479fec..3ecc8434bd 100644 --- a/src/tz/ren/quad.cpp +++ b/src/tz/ren/quad.cpp @@ -16,6 +16,7 @@ namespace tz::ren struct quad_internal_data { tz::trs transform; + bool garbage = false; }; struct quad_renderer_data @@ -31,6 +32,7 @@ namespace tz::ren std::size_t texture_count = 0; unsigned int window_width_cache; unsigned int window_height_cache; + std::vector free_list = {}; }; struct quad_data @@ -141,8 +143,21 @@ namespace tz::ren std::expected quad_renderer_create_quad(quad_renderer_handle renh, quad_info info) { auto& ren = renderers[renh.peek()]; - - quad_internal_data& internal = ren.internals.emplace_back(); + std::size_t id = ren.quad_count; + bool recycled = false; + if(ren.free_list.size()) + { + recycled = true; + id = ren.free_list.back(); + ren.free_list.pop_back(); + } + else + { + ren.internals.push_back({}); + ren.quad_count++; + } + quad_internal_data& internal = ren.internals[id]; + internal = {}; internal.transform = { .translate = {info.position[0], info.position[1], 0.0f}, @@ -163,10 +178,32 @@ namespace tz::ren } } - tz::gpu::pass_set_triangle_count(ren.main_pass, (ren.quad_count + 1) * 2); - tz_must(tz::gpu::resource_write(ren.data_buffer, std::as_bytes(std::span(&new_data, 1)), sizeof(quad_data) * ren.quad_count)); + if(!recycled) + { + tz::gpu::pass_set_triangle_count(ren.main_pass, ren.quad_count * 2); + } + tz_must(tz::gpu::resource_write(ren.data_buffer, std::as_bytes(std::span(&new_data, 1)), sizeof(quad_data) * id)); - return static_cast(ren.quad_count++); + return static_cast(id); + } + + tz::error_code quad_renderer_destroy_quad(quad_renderer_handle renh, quad_handle quad) + { + // quad destruction works as follows: + // set the internal quad data to indicate that the quad is garbage. + // set the scale to zero (the draw is unchanged but the data makes it invisible) + // add to the free list, the next time a quad is created this handle can be re-used. + auto& ren = renderers[renh.peek()]; + auto& q = ren.internals[quad.peek()]; + if(q.garbage) + { + RETERR(tz::error_code::precondition_failure, "attempt to destroy quad {} but it was already destroyed. double delete.", quad.peek()); + } + q = {}; + q.garbage = true; + set_quad_scale(renh, quad, tz::v2f::zero()); + ren.free_list.push_back(quad.peek()); + return tz::error_code::success; } std::expected quad_renderer_add_texture(quad_renderer_handle renh, tz::gpu::resource_handle image)