Optimize sets stickers / gifs panel repainting.

This commit is contained in:
John Preston 2022-01-25 01:55:18 +03:00
parent 1a3a0fb124
commit 51fef843f0
3 changed files with 93 additions and 14 deletions

View file

@ -46,7 +46,7 @@ namespace {
constexpr auto kSearchRequestDelay = 400; constexpr auto kSearchRequestDelay = 400;
constexpr auto kInlineItemsMaxPerRow = 5; constexpr auto kInlineItemsMaxPerRow = 5;
constexpr auto kSearchBotUsername = "gif"_cs; constexpr auto kSearchBotUsername = "gif"_cs;
constexpr auto kMinRepaintDelay = crl::time(16); constexpr auto kMinRepaintDelay = crl::time(33);
constexpr auto kMinAfterScrollDelay = crl::time(33); constexpr auto kMinAfterScrollDelay = crl::time(33);
} // namespace } // namespace
@ -175,9 +175,7 @@ GifsListWidget::GifsListWidget(
, _mosaic(st::emojiPanWidth - st::inlineResultsLeft) , _mosaic(st::emojiPanWidth - st::inlineResultsLeft)
, _previewTimer([=] { showPreview(); }) { , _previewTimer([=] { showPreview(); }) {
setMouseTracking(true); setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
// Otherwise our optimization on repainting is too aggressive.
setAttribute(Qt::WA_OpaquePaintEvent, false);
_inlineRequestTimer.setSingleShot(true); _inlineRequestTimer.setSingleShot(true);
connect( connect(
@ -193,14 +191,14 @@ GifsListWidget::GifsListWidget(
controller->session().downloaderTaskFinished( controller->session().downloaderTaskFinished(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
update(); updateInlineItems();
}, lifetime()); }, lifetime());
controller->gifPauseLevelChanged( controller->gifPauseLevelChanged(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
if (!controller->isGifPausedAtLeastFor( if (!controller->isGifPausedAtLeastFor(
Window::GifPauseReason::SavedGifs)) { Window::GifPauseReason::SavedGifs)) {
update(); updateInlineItems();
} }
}, lifetime()); }, lifetime());
@ -240,10 +238,11 @@ object_ptr<TabbedSelector::InnerFooter> GifsListWidget::createFooter() {
void GifsListWidget::visibleTopBottomUpdated( void GifsListWidget::visibleTopBottomUpdated(
int visibleTop, int visibleTop,
int visibleBottom) { int visibleBottom) {
auto top = getVisibleTop(); const auto top = getVisibleTop();
Inner::visibleTopBottomUpdated(visibleTop, visibleBottom); Inner::visibleTopBottomUpdated(visibleTop, visibleBottom);
if (top != getVisibleTop()) { if (top != getVisibleTop()) {
_lastScrolledAt = crl::now(); _lastScrolledAt = crl::now();
update();
} }
checkLoadMore(); checkLoadMore();
} }

View file

@ -54,6 +54,8 @@ constexpr auto kSearchRequestDelay = 400;
constexpr auto kRecentDisplayLimit = 20; constexpr auto kRecentDisplayLimit = 20;
constexpr auto kPreloadOfficialPages = 4; constexpr auto kPreloadOfficialPages = 4;
constexpr auto kOfficialLoadLimit = 40; constexpr auto kOfficialLoadLimit = 40;
constexpr auto kMinRepaintDelay = crl::time(33);
constexpr auto kMinAfterScrollDelay = crl::time(33);
using Data::StickersSet; using Data::StickersSet;
using Data::StickersPack; using Data::StickersPack;
@ -968,6 +970,8 @@ StickersListWidget::StickersListWidget(
, _api(&controller->session().mtp()) , _api(&controller->session().mtp())
, _section(Section::Stickers) , _section(Section::Stickers)
, _isMasks(masks) , _isMasks(masks)
, _updateItemsTimer([=] { updateItems(); })
, _updateSetsTimer([=] { updateSets(); })
, _pathGradient(std::make_unique<Ui::PathShiftGradient>( , _pathGradient(std::make_unique<Ui::PathShiftGradient>(
st::windowBgRipple, st::windowBgRipple,
st::windowBgOver, st::windowBgOver,
@ -991,7 +995,7 @@ StickersListWidget::StickersListWidget(
session().downloaderTaskFinished( session().downloaderTaskFinished(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
if (isVisible()) { if (isVisible()) {
repaintItems(); updateItems();
readVisibleFeatured(getVisibleTop(), getVisibleBottom()); readVisibleFeatured(getVisibleTop(), getVisibleBottom());
} }
}, lifetime()); }, lifetime());
@ -1065,7 +1069,13 @@ object_ptr<TabbedSelector::InnerFooter> StickersListWidget::createFooter() {
void StickersListWidget::visibleTopBottomUpdated( void StickersListWidget::visibleTopBottomUpdated(
int visibleTop, int visibleTop,
int visibleBottom) { int visibleBottom) {
const auto top = getVisibleTop();
Inner::visibleTopBottomUpdated(visibleTop, visibleBottom); Inner::visibleTopBottomUpdated(visibleTop, visibleBottom);
if (top != getVisibleTop()) {
_lastScrolledAt = crl::now();
_repaintSetsIds.clear();
update();
}
if (_section == Section::Featured) { if (_section == Section::Featured) {
checkVisibleFeatured(visibleTop, visibleBottom); checkVisibleFeatured(visibleTop, visibleBottom);
} else { } else {
@ -1925,7 +1935,7 @@ void StickersListWidget::ensureLottiePlayer(Set &set) {
if (sets[info.section].lottiePlayer.get() != raw) { if (sets[info.section].lottiePlayer.get() != raw) {
return true; return true;
} }
repaintItems(info); updateSet(info);
return false; return false;
}); });
}, set.lottieLifetime); }, set.lottieLifetime);
@ -2000,7 +2010,7 @@ void StickersListWidget::clipCallback(
case Notification::Repaint: break; case Notification::Repaint: break;
} }
repaintItems(info); updateSet(info);
return false; return false;
}); });
} }
@ -2016,16 +2026,73 @@ bool StickersListWidget::itemVisible(
return (visibleTop < bottom) && (visibleBottom > top); 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( update(
0, 0,
info.rowsTop, info.rowsTop,
width(), width(),
info.rowsBottom - info.rowsTop); 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 { QSize StickersListWidget::boundingBoxSize() const {

View file

@ -205,6 +205,7 @@ private:
QString shortName; QString shortName;
std::vector<Sticker> stickers; std::vector<Sticker> stickers;
std::unique_ptr<Ui::RippleAnimation> ripple; std::unique_ptr<Ui::RippleAnimation> ripple;
crl::time lastUpdateTime = 0;
std::unique_ptr<Lottie::MultiPlayer> lottiePlayer; std::unique_ptr<Lottie::MultiPlayer> lottiePlayer;
rpl::lifetime lottieLifetime; rpl::lifetime lottieLifetime;
@ -305,8 +306,13 @@ private:
void takeHeavyData(Sticker &to, Sticker &from); void takeHeavyData(Sticker &to, Sticker &from);
void clearHeavyIn(Set &set, bool clearSavedFrames = true); void clearHeavyIn(Set &set, bool clearSavedFrames = true);
void clearHeavyData(); void clearHeavyData();
void repaintItems(); void updateItems();
void repaintItems(const SectionInfo &info); void updateSets();
void repaintItems(crl::time now = 0);
void updateSet(const SectionInfo &info);
void repaintItems(
const SectionInfo &info,
crl::time now);
int stickersRight() const; int stickersRight() const;
bool featuredHasAddButton(int index) const; bool featuredHasAddButton(int index) const;
@ -364,12 +370,19 @@ private:
base::flat_set<not_null<DocumentData*>> _favedStickersMap; base::flat_set<not_null<DocumentData*>> _favedStickersMap;
std::weak_ptr<Lottie::FrameRenderer> _lottieRenderer; std::weak_ptr<Lottie::FrameRenderer> _lottieRenderer;
crl::time _lastScrolledAt = 0;
crl::time _lastFullUpdatedAt = 0;
mtpRequestId _officialRequestId = 0; mtpRequestId _officialRequestId = 0;
int _officialOffset = 0; int _officialOffset = 0;
Section _section = Section::Stickers; Section _section = Section::Stickers;
const bool _isMasks; const bool _isMasks;
base::Timer _updateItemsTimer;
base::Timer _updateSetsTimer;
base::flat_set<uint64> _repaintSetsIds;
bool _displayingSet = false; bool _displayingSet = false;
uint64 _removingSetId = 0; uint64 _removingSetId = 0;