From 7b11b48317ef411533d5ed8c519e3f195a818d8f Mon Sep 17 00:00:00 2001 From: ns6089 <61738816+ns6089@users.noreply.github.com> Date: Thu, 6 Apr 2023 21:29:21 +0300 Subject: [PATCH] Delayed capture buffer trim --- src/video.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/src/video.cpp b/src/video.cpp index 1b8b682f..86de57de 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -793,36 +793,91 @@ namespace video { } display_wp = disp; - constexpr auto capture_buffer_normal_size = 2; constexpr auto capture_buffer_size = 12; std::list> imgs(capture_buffer_size); + std::vector> imgs_used_timestamps; + const std::chrono::seconds trim_timeot = 3s; + auto trim_imgs = [&]() { + // count allocated and used within current pool + size_t allocated_count = 0; + size_t used_count = 0; + for (const auto &img : imgs) { + if (img) { + allocated_count += 1; + if (img.use_count() > 1) { + used_count += 1; + } + } + } + + // remember the timestamp of currently used count + const auto now = std::chrono::steady_clock::now(); + if (imgs_used_timestamps.size() <= used_count) { + imgs_used_timestamps.resize(used_count + 1); + } + imgs_used_timestamps[used_count] = now; + + // decide whether to trim allocated unused above the currently used count + // based on last used timestamp and universal timeout + size_t trim_target = used_count; + for (size_t i = used_count; i < imgs_used_timestamps.size(); i++) { + if (imgs_used_timestamps[i] && now - *imgs_used_timestamps[i] < trim_timeot) { + trim_target = i; + } + } + + // trim allocated unused above the newly decided trim target + if (allocated_count > trim_target) { + size_t to_trim = allocated_count - trim_target; + // prioritize trimming least recently used + for (auto it = imgs.rbegin(); it != imgs.rend(); it++) { + auto &img = *it; + if (img && img.use_count() == 1) { + img.reset(); + to_trim -= 1; + if (to_trim == 0) break; + } + } + // forget timestamps that no longer relevant + imgs_used_timestamps.resize(trim_target + 1); + } + }; + auto pull_free_image_callback = [&](std::shared_ptr &img_out) -> bool { img_out.reset(); while (capture_ctx_queue->running()) { + // pick first allocated but unused for (auto it = imgs.begin(); it != imgs.end(); it++) { - // pick first unallocated or unused - if (!*it || it->use_count() == 1) { - if (!*it) { - // allocate if unallocated - *it = disp->alloc_img(); - } + if (*it && it->use_count() == 1) { img_out = *it; if (it != imgs.begin()) { - // move freshly allocated or unused img to the front of the list to prioritize its reusal + // move image to the front of the list to prioritize its reusal imgs.erase(it); imgs.push_front(img_out); } break; } } - if (img_out) { - // unallocate unused above normal buffer size - size_t index = 0; - for (auto &img : imgs) { - if (index >= capture_buffer_normal_size && img && img.use_count() == 1) img.reset(); - index++; + // otherwise pick first unallocated + if (!img_out) { + for (auto it = imgs.begin(); it != imgs.end(); it++) { + if (!*it) { + // allocate image + *it = disp->alloc_img(); + img_out = *it; + if (it != imgs.begin()) { + // move image to the front of the list to prioritize its reusal + imgs.erase(it); + imgs.push_front(img_out); + } + break; + } } + } + if (img_out) { + // trim allocated but unused portion of the pool based on timeouts + trim_imgs(); return true; } else {