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 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<TabbedSelector::InnerFooter> 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();
}

View file

@ -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<Ui::PathShiftGradient>(
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<TabbedSelector::InnerFooter> 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 {

View file

@ -205,6 +205,7 @@ private:
QString shortName;
std::vector<Sticker> stickers;
std::unique_ptr<Ui::RippleAnimation> ripple;
crl::time lastUpdateTime = 0;
std::unique_ptr<Lottie::MultiPlayer> 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<not_null<DocumentData*>> _favedStickersMap;
std::weak_ptr<Lottie::FrameRenderer> _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<uint64> _repaintSetsIds;
bool _displayingSet = false;
uint64 _removingSetId = 0;