Add some profiling logs to lottie player.

This commit is contained in:
John Preston 2019-06-29 14:24:46 +02:00
parent 2c461b9df3
commit f6bfbbb805
7 changed files with 111 additions and 32 deletions

View file

@ -1383,7 +1383,7 @@ void StickersListWidget::ensureLottiePlayer(Set &set) {
set.lottiePlayer->updates( set.lottiePlayer->updates(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
const auto &sets = shownSets(); const auto &sets = shownSets();
PROFILE_LOG(("WIDGET REPAINT REQUESTED"));
enumerateSections([&](const SectionInfo &info) { enumerateSections([&](const SectionInfo &info) {
if (shownSets()[info.section].lottiePlayer.get() == raw) { if (shownSets()[info.section].lottiePlayer.get() == raw) {
update( update(

View file

@ -319,6 +319,11 @@ bool DebugEnabled() {
#endif #endif
} }
QString ProfilePrefix() {
const auto now = crl::profile();
return '[' + QString::number(now / 1000., 'f', 3) + "] ";
}
void start(not_null<Core::Launcher*> launcher) { void start(not_null<Core::Launcher*> launcher) {
Assert(LogsData == nullptr); Assert(LogsData == nullptr);

View file

@ -19,6 +19,8 @@ namespace Logs {
void SetDebugEnabled(bool enabled); void SetDebugEnabled(bool enabled);
bool DebugEnabled(); bool DebugEnabled();
QString ProfilePrefix();
void start(not_null<Core::Launcher*> launcher); void start(not_null<Core::Launcher*> launcher);
bool started(); bool started();
void finish(); void finish();
@ -71,6 +73,8 @@ inline MemoryBuffer mb(const void *ptr, uint32 size) {
#define LOG(msg) (Logs::writeMain(QString msg)) #define LOG(msg) (Logs::writeMain(QString msg))
//usage LOG(("log: %1 %2").arg(1).arg(2)) //usage LOG(("log: %1 %2").arg(1).arg(2))
#define PROFILE_LOG(msg) (Logs::writeMain(Logs::ProfilePrefix() + QString msg))
#define DEBUG_LOG(msg) {\ #define DEBUG_LOG(msg) {\
if (Logs::DebugEnabled() || !Logs::started()) {\ if (Logs::DebugEnabled() || !Logs::started()) {\
Logs::writeDebug(SOURCE_FILE_BASENAME, __LINE__, QString msg);\ Logs::writeDebug(SOURCE_FILE_BASENAME, __LINE__, QString msg);\

View file

@ -10,11 +10,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lottie/lottie_player.h" #include "lottie/lottie_player.h"
#include "lottie/lottie_animation.h" #include "lottie/lottie_animation.h"
#include "lottie/lottie_cache.h" #include "lottie/lottie_cache.h"
#include "rlottie.h" #include "base/flat_map.h"
#include "logs.h"
#include <QPainter>
#include <rlottie.h>
#include <range/v3/algorithm/find.hpp> #include <range/v3/algorithm/find.hpp>
#include <range/v3/algorithm/count_if.hpp> #include <range/v3/algorithm/count_if.hpp>
#include <QPainter>
namespace Images { namespace Images {
QImage prepareColored(QColor add, QImage image); QImage prepareColored(QColor add, QImage image);
@ -158,11 +160,30 @@ void FrameRendererObject::remove(not_null<SharedState*> entry) {
} }
void FrameRendererObject::generateFrames() { void FrameRendererObject::generateFrames() {
const auto renderOne = [&](const Entry & entry) { auto players = base::flat_map<Player*, base::weak_ptr<Player>>();
return entry.state->renderNextFrame(entry.request); const auto renderOne = [&](const Entry &entry) {
const auto result = entry.state->renderNextFrame(entry.request);
if (const auto player = result.notify.get()) {
players.emplace(player, result.notify);
}
return result.rendered;
}; };
if (ranges::count_if(_entries, renderOne) > 0) { const auto rendered = ranges::count_if(_entries, renderOne);
if (rendered) {
PROFILE_LOG(("RENDERER: %1, ALL: %2, PLAYERS: %3").arg(rendered).arg(_entries.size()).arg(players.size()));
if (!players.empty()) {
crl::on_main([players = std::move(players)] {
for (const auto &[player, weak] : players) {
if (weak) {
PROFILE_LOG(("RENDERER -- ON MAIN CHECK"));
weak->checkStep();
}
}
});
}
queueGenerateFrames(); queueGenerateFrames();
} else {
PROFILE_LOG(("RENDERER EMPTY"));
} }
} }
@ -311,20 +332,21 @@ void SharedState::renderNextFrame(
frame->displayed = kTimeUnknown; frame->displayed = kTimeUnknown;
} }
bool SharedState::renderNextFrame(const FrameRequest &request) { auto SharedState::renderNextFrame(const FrameRequest &request)
const auto prerender = [&](int index) { -> RenderResult {
const auto prerender = [&](int index) -> RenderResult {
const auto frame = getFrame(index); const auto frame = getFrame(index);
const auto next = getFrame((index + 1) % kFramesCount); const auto next = getFrame((index + 1) % kFramesCount);
if (!IsRendered(frame)) { if (!IsRendered(frame)) {
renderNextFrame(frame, request); renderNextFrame(frame, request);
return true; return { true };
} else if (!IsRendered(next)) { } else if (!IsRendered(next)) {
renderNextFrame(next, request); renderNextFrame(next, request);
return true; return { true };
} }
return false; return { false };
}; };
const auto present = [&](int counter, int index) { const auto present = [&](int counter, int index) -> RenderResult {
const auto frame = getFrame(index); const auto frame = getFrame(index);
if (!IsRendered(frame)) { if (!IsRendered(frame)) {
renderNextFrame(frame, request); renderNextFrame(frame, request);
@ -335,10 +357,7 @@ bool SharedState::renderNextFrame(const FrameRequest &request) {
_counter.store( _counter.store(
(counter + 1) % (2 * kFramesCount), (counter + 1) % (2 * kFramesCount),
std::memory_order_release); std::memory_order_release);
crl::on_main(_owner, [=] { return { true, _owner };
_owner->checkStep();
});
return true;
}; };
switch (counter()) { switch (counter()) {
@ -401,7 +420,7 @@ crl::time SharedState::nextFrameDisplayTime() const {
const auto frame = getFrame(index); const auto frame = getFrame(index);
if (frame->displayed != kTimeUnknown) { if (frame->displayed != kTimeUnknown) {
// Frame already displayed, but not yet shown. // Frame already displayed, but not yet shown.
return kTimeUnknown; return kFrameDisplayTimeAlreadyDone;
} }
Assert(IsRendered(frame)); Assert(IsRendered(frame));
Assert(frame->display != kTimeUnknown); Assert(frame->display != kTimeUnknown);

View file

@ -26,6 +26,8 @@ namespace Lottie {
inline constexpr auto kMaxFrameRate = 120; inline constexpr auto kMaxFrameRate = 120;
inline constexpr auto kMaxSize = 3096; inline constexpr auto kMaxSize = 3096;
inline constexpr auto kMaxFramesCount = 600; inline constexpr auto kMaxFramesCount = 600;
inline constexpr auto kFrameDisplayTimeAlreadyDone
= std::numeric_limits<crl::time>::max();
class Player; class Player;
class Cache; class Cache;
@ -66,7 +68,12 @@ public:
crl::time markFrameShown(); crl::time markFrameShown();
void renderFrame(QImage &image, const FrameRequest &request, int index); void renderFrame(QImage &image, const FrameRequest &request, int index);
[[nodiscard]] bool renderNextFrame(const FrameRequest &request);
struct RenderResult {
bool rendered = false;
base::weak_ptr<Player> notify;
};
[[nodiscard]] RenderResult renderNextFrame(const FrameRequest &request);
~SharedState(); ~SharedState();

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lottie/lottie_frame_renderer.h" #include "lottie/lottie_frame_renderer.h"
#include "lottie/lottie_animation.h" #include "lottie/lottie_animation.h"
#include "logs.h"
#include <range/v3/algorithm/remove.hpp> #include <range/v3/algorithm/remove.hpp>
@ -19,7 +20,8 @@ std::shared_ptr<FrameRenderer> MakeFrameRenderer() {
} }
MultiPlayer::MultiPlayer(std::shared_ptr<FrameRenderer> renderer) MultiPlayer::MultiPlayer(std::shared_ptr<FrameRenderer> renderer)
: _renderer(renderer ? std::move(renderer) : FrameRenderer::Instance()) { : _timer([=] { checkNextFrameRender(); })
, _renderer(renderer ? std::move(renderer) : FrameRenderer::Instance()) {
} }
MultiPlayer::~MultiPlayer() { MultiPlayer::~MultiPlayer() {
@ -125,7 +127,9 @@ rpl::producer<MultiUpdate> MultiPlayer::updates() const {
} }
void MultiPlayer::checkStep() { void MultiPlayer::checkStep() {
if (_nextFrameTime != kTimeUnknown) { if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
return;
} else if (_nextFrameTime != kTimeUnknown) {
checkNextFrameRender(); checkNextFrameRender();
} else { } else {
checkNextFrameAvailability(); checkNextFrameAvailability();
@ -133,6 +137,8 @@ void MultiPlayer::checkStep() {
} }
void MultiPlayer::checkNextFrameAvailability() { void MultiPlayer::checkNextFrameAvailability() {
Expects(_nextFrameTime == kTimeUnknown);
if (_active.empty()) { if (_active.empty()) {
return; return;
} }
@ -140,13 +146,25 @@ void MultiPlayer::checkNextFrameAvailability() {
for (const auto &[animation, state] : _active) { for (const auto &[animation, state] : _active) {
const auto time = state->nextFrameDisplayTime(); const auto time = state->nextFrameDisplayTime();
if (time == kTimeUnknown) { if (time == kTimeUnknown) {
for (const auto &[animation, state] : _active) {
if (state->nextFrameDisplayTime() != kTimeUnknown) {
PROFILE_LOG(("PLAYER -------- SOME READY, BUT NOT ALL"));
break;
}
}
return; return;
} else if (time == kFrameDisplayTimeAlreadyDone) {
continue;
} }
if (next == kTimeUnknown || next > time) { if (next == kTimeUnknown || next > time) {
next = time; next = time;
} }
} }
Assert(next != kTimeUnknown); if (next == kTimeUnknown) {
PROFILE_LOG(("PLAYER ALL DISPLAYED, WAITING PAINT."));
return;
}
PROFILE_LOG(("PLAYER NEXT FRAME TIME: %1").arg(next));
_nextFrameTime = next; _nextFrameTime = next;
checkNextFrameRender(); checkNextFrameRender();
} }
@ -157,15 +175,17 @@ void MultiPlayer::checkNextFrameRender() {
const auto now = crl::now(); const auto now = crl::now();
if (now < _nextFrameTime) { if (now < _nextFrameTime) {
if (!_timer.isActive()) { if (!_timer.isActive()) {
PROFILE_LOG(("PLAYER TIMER FOR: %1").arg(_nextFrameTime - now));
_timer.callOnce(_nextFrameTime - now); _timer.callOnce(_nextFrameTime - now);
} }
} else { } else {
_timer.cancel(); _timer.cancel();
const auto exact = std::exchange(_nextFrameTime, kTimeUnknown); const auto exact = std::exchange(
_nextFrameTime,
kFrameDisplayTimeAlreadyDone);
markFrameDisplayed(now, now - exact); markFrameDisplayed(now, now - exact);
_updates.fire({}); _updates.fire({});
checkStep();
} }
} }
@ -181,23 +201,37 @@ void MultiPlayer::updateFrameRequest(
void MultiPlayer::markFrameDisplayed(crl::time now, crl::time delayed) { void MultiPlayer::markFrameDisplayed(crl::time now, crl::time delayed) {
Expects(!_active.empty()); Expects(!_active.empty());
auto displayed = 0;
auto waiting = 0;
for (const auto &[animation, state] : _active) { for (const auto &[animation, state] : _active) {
const auto time = state->nextFrameDisplayTime(); const auto time = state->nextFrameDisplayTime();
Assert(time != kTimeUnknown); Assert(time != kTimeUnknown);
if (now >= time) { if (time == kFrameDisplayTimeAlreadyDone) {
continue;
} else if (now >= time) {
++displayed;
state->markFrameDisplayed(now, delayed); state->markFrameDisplayed(now, delayed);
} else {
++waiting;
} }
} }
PROFILE_LOG(("PLAYER FRAME DISPLAYED AT: %1, DELAYED: %2, (MARKED %3, WAITING %4)").arg(now).arg(delayed).arg(displayed).arg(waiting));
} }
void MultiPlayer::markFrameShown() { void MultiPlayer::markFrameShown() {
if (_active.empty()) { if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
return; _nextFrameTime = kTimeUnknown;
} }
auto count = 0;
for (const auto &[animation, state] : _active) { for (const auto &[animation, state] : _active) {
state->markFrameShown(); if (state->markFrameShown() != kTimeUnknown) {
++count;
}
}
PROFILE_LOG(("PLAYER MARKED SHOWN %1 OF %2").arg(count).arg(_active.size()));
if (count) {
_renderer->frameShown();
} }
_renderer->frameShown();
} }
} // namespace Lottie } // namespace Lottie

View file

@ -71,7 +71,9 @@ QImage SinglePlayer::frame(const FrameRequest &request) const {
} }
void SinglePlayer::checkStep() { void SinglePlayer::checkStep() {
if (_nextFrameTime != kTimeUnknown) { if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
return;
} else if (_nextFrameTime != kTimeUnknown) {
checkNextFrameRender(); checkNextFrameRender();
} else { } else {
checkNextFrameAvailability(); checkNextFrameAvailability();
@ -80,8 +82,10 @@ void SinglePlayer::checkStep() {
void SinglePlayer::checkNextFrameAvailability() { void SinglePlayer::checkNextFrameAvailability() {
Expects(_state != nullptr); Expects(_state != nullptr);
Expects(_nextFrameTime == kTimeUnknown);
_nextFrameTime = _state->nextFrameDisplayTime(); _nextFrameTime = _state->nextFrameDisplayTime();
Assert(_nextFrameTime != kFrameDisplayTimeAlreadyDone);
if (_nextFrameTime != kTimeUnknown) { if (_nextFrameTime != kTimeUnknown) {
checkNextFrameRender(); checkNextFrameRender();
} }
@ -98,7 +102,9 @@ void SinglePlayer::checkNextFrameRender() {
} else { } else {
_timer.cancel(); _timer.cancel();
const auto exact = std::exchange(_nextFrameTime, kTimeUnknown); const auto exact = std::exchange(
_nextFrameTime,
kFrameDisplayTimeAlreadyDone);
const auto position = _state->markFrameDisplayed(now, now - exact); const auto position = _state->markFrameDisplayed(now, now - exact);
_updates.fire({ DisplayFrameRequest{ position } }); _updates.fire({ DisplayFrameRequest{ position } });
} }
@ -116,8 +122,12 @@ void SinglePlayer::updateFrameRequest(
void SinglePlayer::markFrameShown() { void SinglePlayer::markFrameShown() {
Expects(_state != nullptr); Expects(_state != nullptr);
_state->markFrameShown(); if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
_renderer->frameShown(); _nextFrameTime = kTimeUnknown;
}
if (_state->markFrameShown() != kTimeUnknown) {
_renderer->frameShown();
}
} }
} // namespace Lottie } // namespace Lottie