From 51fef843f0193d8c3c465a1e22ce202b23225c0a Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jan 2022 01:55:18 +0300 Subject: [PATCH] Optimize sets stickers / gifs panel repainting. --- .../chat_helpers/gifs_list_widget.cpp | 13 ++-- .../chat_helpers/stickers_list_widget.cpp | 77 +++++++++++++++++-- .../chat_helpers/stickers_list_widget.h | 17 +++- 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 924a0c6d0..60d3ae7bf 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -46,7 +46,7 @@ namespace { constexpr auto kSearchRequestDelay = 400; constexpr auto kInlineItemsMaxPerRow = 5; constexpr auto kSearchBotUsername = "gif"_cs; -constexpr auto kMinRepaintDelay = crl::time(16); +constexpr auto kMinRepaintDelay = crl::time(33); constexpr auto kMinAfterScrollDelay = crl::time(33); } // namespace @@ -175,9 +175,7 @@ GifsListWidget::GifsListWidget( , _mosaic(st::emojiPanWidth - st::inlineResultsLeft) , _previewTimer([=] { showPreview(); }) { setMouseTracking(true); - - // Otherwise our optimization on repainting is too aggressive. - setAttribute(Qt::WA_OpaquePaintEvent, false); + setAttribute(Qt::WA_OpaquePaintEvent); _inlineRequestTimer.setSingleShot(true); connect( @@ -193,14 +191,14 @@ GifsListWidget::GifsListWidget( controller->session().downloaderTaskFinished( ) | rpl::start_with_next([=] { - update(); + updateInlineItems(); }, lifetime()); controller->gifPauseLevelChanged( ) | rpl::start_with_next([=] { if (!controller->isGifPausedAtLeastFor( Window::GifPauseReason::SavedGifs)) { - update(); + updateInlineItems(); } }, lifetime()); @@ -240,10 +238,11 @@ object_ptr GifsListWidget::createFooter() { void GifsListWidget::visibleTopBottomUpdated( int visibleTop, int visibleBottom) { - auto top = getVisibleTop(); + const auto top = getVisibleTop(); Inner::visibleTopBottomUpdated(visibleTop, visibleBottom); if (top != getVisibleTop()) { _lastScrolledAt = crl::now(); + update(); } checkLoadMore(); } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index cac6dfc5b..306f7caeb 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -54,6 +54,8 @@ constexpr auto kSearchRequestDelay = 400; constexpr auto kRecentDisplayLimit = 20; constexpr auto kPreloadOfficialPages = 4; constexpr auto kOfficialLoadLimit = 40; +constexpr auto kMinRepaintDelay = crl::time(33); +constexpr auto kMinAfterScrollDelay = crl::time(33); using Data::StickersSet; using Data::StickersPack; @@ -968,6 +970,8 @@ StickersListWidget::StickersListWidget( , _api(&controller->session().mtp()) , _section(Section::Stickers) , _isMasks(masks) +, _updateItemsTimer([=] { updateItems(); }) +, _updateSetsTimer([=] { updateSets(); }) , _pathGradient(std::make_unique( st::windowBgRipple, st::windowBgOver, @@ -991,7 +995,7 @@ StickersListWidget::StickersListWidget( session().downloaderTaskFinished( ) | rpl::start_with_next([=] { if (isVisible()) { - repaintItems(); + updateItems(); readVisibleFeatured(getVisibleTop(), getVisibleBottom()); } }, lifetime()); @@ -1065,7 +1069,13 @@ object_ptr StickersListWidget::createFooter() { void StickersListWidget::visibleTopBottomUpdated( int visibleTop, int visibleBottom) { + const auto top = getVisibleTop(); Inner::visibleTopBottomUpdated(visibleTop, visibleBottom); + if (top != getVisibleTop()) { + _lastScrolledAt = crl::now(); + _repaintSetsIds.clear(); + update(); + } if (_section == Section::Featured) { checkVisibleFeatured(visibleTop, visibleBottom); } else { @@ -1925,7 +1935,7 @@ void StickersListWidget::ensureLottiePlayer(Set &set) { if (sets[info.section].lottiePlayer.get() != raw) { return true; } - repaintItems(info); + updateSet(info); return false; }); }, set.lottieLifetime); @@ -2000,7 +2010,7 @@ void StickersListWidget::clipCallback( case Notification::Repaint: break; } - repaintItems(info); + updateSet(info); return false; }); } @@ -2016,16 +2026,73 @@ bool StickersListWidget::itemVisible( return (visibleTop < bottom) && (visibleBottom > top); } -void StickersListWidget::repaintItems(const SectionInfo &info) { +void StickersListWidget::updateSets() { + if (_repaintSetsIds.empty()) { + return; + } + auto repaint = base::take(_repaintSetsIds); + auto &sets = shownSets(); + enumerateSections([&](const SectionInfo &info) { + if (repaint.contains(sets[info.section].id)) { + updateSet(info); + } + return true; + }); +} + +void StickersListWidget::updateSet(const SectionInfo &info) { + auto &set = shownSets()[info.section]; + + const auto now = crl::now(); + const auto delay = std::max( + _lastScrolledAt + kMinAfterScrollDelay - now, + set.lastUpdateTime + kMinRepaintDelay - now); + if (delay <= 0) { + repaintItems(info, now); + } else { + _repaintSetsIds.emplace(set.id); + if (!_updateSetsTimer.isActive() + || _updateSetsTimer.remainingTime() > kMinRepaintDelay) { + _updateSetsTimer.callOnce(std::max(delay, kMinRepaintDelay)); + } + } +} + +void StickersListWidget::repaintItems( + const SectionInfo &info, + crl::time now) { update( 0, info.rowsTop, width(), info.rowsBottom - info.rowsTop); + auto &set = shownSets()[info.section]; + set.lastUpdateTime = now; } -void StickersListWidget::repaintItems() { +void StickersListWidget::updateItems() { + const auto now = crl::now(); + const auto delay = std::max( + _lastScrolledAt + kMinAfterScrollDelay - now, + _lastFullUpdatedAt + kMinRepaintDelay - now); + if (delay <= 0) { + repaintItems(now); + } else if (!_updateItemsTimer.isActive() + || _updateItemsTimer.remainingTime() > kMinRepaintDelay) { + _updateItemsTimer.callOnce(std::max(delay, kMinRepaintDelay)); + } +} +void StickersListWidget::repaintItems(crl::time now) { + update(); + _repaintSetsIds.clear(); + if (!now) { + now = crl::now(); + } + _lastFullUpdatedAt = now; + for (auto &set : shownSets()) { + set.lastUpdateTime = now; + } } QSize StickersListWidget::boundingBoxSize() const { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index 80a81136b..396a3b985 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -205,6 +205,7 @@ private: QString shortName; std::vector stickers; std::unique_ptr ripple; + crl::time lastUpdateTime = 0; std::unique_ptr lottiePlayer; rpl::lifetime lottieLifetime; @@ -305,8 +306,13 @@ private: void takeHeavyData(Sticker &to, Sticker &from); void clearHeavyIn(Set &set, bool clearSavedFrames = true); void clearHeavyData(); - void repaintItems(); - void repaintItems(const SectionInfo &info); + void updateItems(); + void updateSets(); + void repaintItems(crl::time now = 0); + void updateSet(const SectionInfo &info); + void repaintItems( + const SectionInfo &info, + crl::time now); int stickersRight() const; bool featuredHasAddButton(int index) const; @@ -364,12 +370,19 @@ private: base::flat_set> _favedStickersMap; std::weak_ptr _lottieRenderer; + crl::time _lastScrolledAt = 0; + crl::time _lastFullUpdatedAt = 0; + mtpRequestId _officialRequestId = 0; int _officialOffset = 0; Section _section = Section::Stickers; const bool _isMasks; + base::Timer _updateItemsTimer; + base::Timer _updateSetsTimer; + base::flat_set _repaintSetsIds; + bool _displayingSet = false; uint64 _removingSetId = 0;