mirror of
https://github.com/vale981/tdesktop
synced 2025-03-05 17:51:41 -05:00
Add some profiling logs to lottie player.
This commit is contained in:
parent
2c461b9df3
commit
f6bfbbb805
7 changed files with 111 additions and 32 deletions
|
@ -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(
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);\
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue