Delayed capture buffer trim

This commit is contained in:
ns6089 2023-04-06 21:29:21 +03:00 committed by Cameron Gutman
parent 242a146712
commit 7b11b48317

View File

@ -793,36 +793,91 @@ namespace video {
}
display_wp = disp;
constexpr auto capture_buffer_normal_size = 2;
constexpr auto capture_buffer_size = 12;
std::list<std::shared_ptr<platf::img_t>> imgs(capture_buffer_size);
std::vector<std::optional<std::chrono::steady_clock::time_point>> 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<platf::img_t> &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 {