From 4907c5cc952e94e32cb0f95ea6f3be361b55d389 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 3 Oct 2020 14:46:57 +0200 Subject: Reduce memory usage by cleaning up text not visible on the screen As a text, memory usage decreased from 150mb to 20mb --- src/Body.cpp | 132 ++++++++++++++++++++++++++++++++++++++--------------------- src/Text.cpp | 24 ----------- 2 files changed, 85 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index 812840d..08ef690 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -23,7 +23,8 @@ namespace QuickMedia { thumbnail_is_local(false), title_color(sf::Color::White), author_color(sf::Color::White), - userdata(nullptr) + userdata(nullptr), + last_drawn_time(0) { if(!_title.empty()) set_title(std::move(_title)); @@ -58,6 +59,7 @@ namespace QuickMedia { title_color = other.title_color; author_color = other.author_color; userdata = other.userdata; + last_drawn_time = other.last_drawn_time; } Body::Body(Program *program, sf::Font *font, sf::Font *bold_font, sf::Font *cjk_font) : @@ -279,6 +281,8 @@ namespace QuickMedia { sf::Vector2f scissor_size = size; const float start_y = pos.y; + const sf::Int32 elapsed_time = draw_timer.getElapsedTime().asMilliseconds(); + if(thumbnail_resize_target_size.x != 0 && thumbnail_resize_target_size.y != 0) { image_max_height = thumbnail_resize_target_size.y; } @@ -294,11 +298,9 @@ namespace QuickMedia { int num_items = items.size(); if(num_items == 0 || size.y <= 0.0f) { - for(auto it = item_thumbnail_textures.begin(); it != item_thumbnail_textures.end();) { - if(!it->second->referenced) - it = item_thumbnail_textures.erase(it); - else - ++it; + item_thumbnail_textures.clear(); + for(auto &body_item : items) { + clear_body_item_cache(body_item.get()); } return; } @@ -307,41 +309,6 @@ namespace QuickMedia { thumbnail_it.second->referenced = false; } - for(auto &body_item : items) { - if(body_item->dirty) { - body_item->dirty = false; - // TODO: Find a way to optimize fromUtf8 - sf::String str = sf::String::fromUtf8(body_item->get_title().data(), body_item->get_title().data() + body_item->get_title().size()); - if(body_item->title_text) - body_item->title_text->setString(std::move(str)); - else - body_item->title_text = std::make_unique(std::move(str), font, cjk_font, 16, size.x - 50 - image_padding_x * 2.0f); - body_item->title_text->setFillColor(body_item->title_color); - body_item->title_text->updateGeometry(); - } - - if(body_item->dirty_description) { - body_item->dirty_description = false; - sf::String str = sf::String::fromUtf8(body_item->get_description().data(), body_item->get_description().data() + body_item->get_description().size()); - if(body_item->description_text) - body_item->description_text->setString(std::move(str)); - else - body_item->description_text = std::make_unique(std::move(str), font, cjk_font, 14, size.x - 50 - image_padding_x * 2.0f); - body_item->description_text->updateGeometry(); - } - - if(body_item->dirty_author) { - body_item->dirty_author = false; - sf::String str = sf::String::fromUtf8(body_item->get_author().data(), body_item->get_author().data() + body_item->get_author().size()); - if(body_item->author_text) - body_item->author_text->setString(std::move(str)); - else - body_item->author_text = std::make_unique(std::move(str), bold_font, cjk_font, 14, size.x - 50 - image_padding_x * 2.0f); - body_item->author_text->setFillColor(body_item->author_color); - body_item->author_text->updateGeometry(); - } - } - if(prev_selected_item < 0 || prev_selected_item >= (int)items.size()) { prev_selected_item = selected_item; } @@ -384,8 +351,6 @@ namespace QuickMedia { pos.y += page_scroll; sf::Vector2u window_size = window.getSize(); - glEnable(GL_SCISSOR_TEST); - glScissor(scissor_pos.x, (int)window_size.y - (int)scissor_pos.y - (int)scissor_size.y, scissor_size.x, scissor_size.y); sf::Vector2f prev_pos = pos; for(int i = selected_item - 1; i >= 0; --i) { @@ -395,13 +360,20 @@ namespace QuickMedia { if(!item->visible) continue; + update_dirty_state(item.get(), size); + float item_height = get_item_height(item.get()); prev_pos.y -= (item_height + spacing_y); if(prev_pos.y + item_height + spacing_y < start_y) break; + item->last_drawn_time = elapsed_time; + // This is needed here rather than above the loop, since update_dirty_text cant be called inside scissor because it corrupts the text for some reason + glEnable(GL_SCISSOR_TEST); + glScissor(scissor_pos.x, (int)window_size.y - (int)scissor_pos.y - (int)scissor_size.y, scissor_size.x, scissor_size.y); draw_item(window, item.get(), prev_pos, size, item_height, i, content_progress); + glDisable(GL_SCISSOR_TEST); ++num_visible_items; } @@ -413,6 +385,8 @@ namespace QuickMedia { if(!item->visible) continue; + update_dirty_state(item.get(), size); + float item_height = get_item_height(item.get()); if((after_pos.y - start_y) + item_height + spacing_y > size.y) @@ -423,7 +397,12 @@ namespace QuickMedia { if(after_pos.y - start_y >= size.y) break; + item->last_drawn_time = elapsed_time; + // This is needed here rather than above the loop, since update_dirty_text cant be called inside scissor because it corrupts the text for some reason + glEnable(GL_SCISSOR_TEST); + glScissor(scissor_pos.x, (int)window_size.y - (int)scissor_pos.y - (int)scissor_size.y, scissor_size.x, scissor_size.y); draw_item(window, item.get(), after_pos, size, item_height, i, content_progress); + glDisable(GL_SCISSOR_TEST); after_pos.y += item_height + spacing_y; ++num_visible_items; } @@ -431,17 +410,76 @@ namespace QuickMedia { if(last_fully_visible_item == -1) last_fully_visible_item = selected_item; - glDisable(GL_SCISSOR_TEST); - for(auto it = item_thumbnail_textures.begin(); it != item_thumbnail_textures.end();) { if(!it->second->referenced) it = item_thumbnail_textures.erase(it); else ++it; } + + // TODO: Only do this for items that are not visible, do not loop all items. + // TODO: Verify if this only runs for items that are not visible, and only once + // TODO: Improve performance! right now it can use up to 5-7% cpu with a lot of items! + for(auto &body_item : items) { + if(elapsed_time - body_item->last_drawn_time >= 1500) { + clear_body_item_cache(body_item.get()); + } + } + } + + void Body::update_dirty_state(BodyItem *body_item, sf::Vector2f size) { + if(body_item->dirty) { + body_item->dirty = false; + // TODO: Find a way to optimize fromUtf8 + sf::String str = sf::String::fromUtf8(body_item->get_title().data(), body_item->get_title().data() + body_item->get_title().size()); + if(body_item->title_text) + body_item->title_text->setString(std::move(str)); + else + body_item->title_text = std::make_unique(std::move(str), font, cjk_font, 16, size.x - 50 - image_padding_x * 2.0f); + body_item->title_text->setFillColor(body_item->title_color); + body_item->title_text->updateGeometry(); + } + + if(body_item->dirty_description) { + body_item->dirty_description = false; + sf::String str = sf::String::fromUtf8(body_item->get_description().data(), body_item->get_description().data() + body_item->get_description().size()); + if(body_item->description_text) + body_item->description_text->setString(std::move(str)); + else + body_item->description_text = std::make_unique(std::move(str), font, cjk_font, 14, size.x - 50 - image_padding_x * 2.0f); + body_item->description_text->updateGeometry(); + } + + if(body_item->dirty_author) { + body_item->dirty_author = false; + sf::String str = sf::String::fromUtf8(body_item->get_author().data(), body_item->get_author().data() + body_item->get_author().size()); + if(body_item->author_text) + body_item->author_text->setString(std::move(str)); + else + body_item->author_text = std::make_unique(std::move(str), bold_font, cjk_font, 14, size.x - 50 - image_padding_x * 2.0f); + body_item->author_text->setFillColor(body_item->author_color); + body_item->author_text->updateGeometry(); + } + } + + void Body::clear_body_item_cache(BodyItem *body_item) { + if(body_item->title_text) { + body_item->title_text.reset(); + body_item->dirty = true; + } + if(body_item->description_text) { + body_item->description_text.reset(); + body_item->dirty_description = true; + } + if(body_item->author_text) { + body_item->author_text.reset(); + body_item->dirty_author = true; + } } void Body::draw_item(sf::RenderWindow &window, BodyItem *item, sf::Vector2f pos, sf::Vector2f size) { + update_dirty_state(item, size); + item->last_drawn_time = draw_timer.getElapsedTime().asMilliseconds(); sf::Vector2u window_size = window.getSize(); glEnable(GL_SCISSOR_TEST); glScissor(pos.x, (int)window_size.y - (int)pos.y - (int)size.y, size.x, size.y); @@ -574,10 +612,10 @@ namespace QuickMedia { float Body::get_item_height(BodyItem *item) { float item_height = 0.0f; - if(!item->get_title().empty()) { + if(item->title_text) { item_height += item->title_text->getHeight() - 2.0f; } - if(!item->get_author().empty()) { + if(item->author_text) { item_height += item->author_text->getHeight() - 2.0f; } if(item->description_text) { diff --git a/src/Text.cpp b/src/Text.cpp index 2165037..e311f14 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -37,7 +37,6 @@ namespace QuickMedia dirtyText(false), dirtyCaret(false), editable(false), - visible(true), caretMoveDirection(CaretMoveDirection::NONE), lineSpacing(0.0f), characterSpacing(0.0f), @@ -707,32 +706,10 @@ namespace QuickMedia } sf::Vector2f pos = position; - - // TODO: Do not use maxWidth here. Max width might be set to 99999 and actual text width might be 200. Text width should be calculated instead - //sf::FloatRect targetRect(0.0f, 0.0f, maxWidth, target.getSize().y); - //sf::FloatRect textRect(pos.x, pos.y, maxWidth, ) - //colRect.contains() - //if(pos.x + maxWidth <= 0.0f || pos.x >= maxWidth || pos.y + totalHeight <= 0.0f || pos.y >= target.getSize().y) return; - renderTargetSize = target.getSize(); - if(pos.y + getHeight() <= 0.0f || pos.y >= renderTargetSize.y) - { - if(!editable && visible && lastSeenTimer.getElapsedTime().asMilliseconds() > 3000) - { - visible = false; - vertices[0].resize(0); - vertices[1].resize(0); - } - return false; - } const float vspace = font->getLineSpacing(characterSize); pos.y += floor(vspace); // Origin is at bottom left, we want it to be at top left - if(!visible) { - visible = true; - updateGeometry(true); - } - const sf::Font *fonts[] = { font, cjk_font }; for(size_t i = 0; i < 2; ++i) { sf::RenderStates states; @@ -740,7 +717,6 @@ namespace QuickMedia states.texture = &fonts[i]->getTexture(characterSize); target.draw(vertices[i], states); } - lastSeenTimer.restart(); if(!editable) return true; pos.y -= floor(vspace * 2.0f); -- cgit v1.2.3